character.getProperty()
Read a value from the character behind the token — the sheet, not the token's copy of it.
Part of the Action API · Function reference
Available on character, which is null when the token is not linked to a
character. Check before using it:
if (!character) return 'This token has no character sheet.';
Signature
character.getProperty(propertyName: string): unknown
Synchronous. Read-only — there is no character.setProperty().
Parameters
| Parameter | Type | Description |
|---|---|---|
propertyName |
string |
An attribute name, a metadata key, or one of the exposed top-level fields. Case-insensitive. |
Returns
The value, or undefined when the name matches nothing or names something the
character API does not expose.
What it can see
Three places are searched, in order, and the first match wins:
- Attributes — the character's own attributes, returned as the computed
value: the number shown on the sheet, with every component and floor
already applied. This is the main reason to use
characterrather thantoken. - Metadata — the character's metadata map, matched case-insensitively.
- A short list of top-level fields —
name,level,systemId,classes, andorigins. Nothing else.
Everything else on a character is deliberately out of reach: skills, feats,
attacks, notes, raw artwork records, ids, and the rest all return undefined.
The character API is a small, stable window onto the sheet, not a view of its
internals.
character versus token
They answer different questions, and the difference matters:
token.getProperty() |
character.getProperty() |
|
|---|---|---|
| Reads | The token's own stored values | The character sheet |
| Attributes | Whatever was projected onto the token | The computed value, live from the sheet |
| Writable | Yes, via setProperty() |
No |
| Available | Always | Only when the token is linked to a character |
A token's values can drift from its character's — that is what makes a
temporarily buffed minion possible. Read token for the state of this figure
on the map, and character for what the sheet says.
Examples
Guard, then read
if (!character) return `${token.name} has no character sheet.`;
const str = character.getProperty('Strength');
sendMessage(`${character.getProperty('name')} — Strength ${str}`);
Scale an effect by level
const level = Number(character.getProperty('level') ?? 1);
const damage = roll(`${Math.ceil(level / 2)}d6`, { label: 'Searing Smite' });
target?.applyDamage(damage, 'radiant');
Fall back to the token
const wis = character?.getProperty('Wisdom') ?? token.getProperty('wis') ?? 10;
Compare sheet against token
const sheet = character?.getProperty('Dexterity');
const onMap = token.getProperty('dex');
if (sheet !== undefined && sheet !== onMap) {
sendMessage(`<i>${token.name} is running on modified Dexterity (${onMap} vs ${sheet}).</i>`);
}
Notes and gotchas
characteris oftennull. Monsters, scenery, and hand-placed tokens have no sheet. Every use needs a guard or?..- Read-only, and that is the design. Use
setProperty()on the token to change anything. - Attribute names, as the sheet spells them. Resolution here is a plain
case-insensitive name match — it does not follow the alias and id chain that
token.getProperty()does, so'str'may miss where'Strength'hits. undefinedis ambiguous. It means "not found or not exposed".