Skip to main content
Targeting is how Fireweave decides which value a control point returns for a given identity. A target is that identity — a user or device keyed by targetingKey — optionally carrying durable properties stored by fw-server. You own the ID. The SDK never auto-generates one. The wire still says flagKey for the control point. Identity on that call is always targetingKey.

Why it exists

Percentage assignment hashes on targetingKey. If the key changes every request, users flip variants. Registration exists so durable facts (plan, region, device model) do not have to ride on every evaluate.

When to use it

user, org, plan, and region are not reserved SDK fields. kind on register is 'user' or 'device'. plan and region appear in examples as property names you may send — you choose the keys.
Do not mint a fresh UUID per request. Do not use request IDs or timestamps. Prefer opaque IDs over email addresses. The SDK forwards the key verbatim and does not hash or rotate it.A constant targeting key hashes every caller into one bucket. That makes a percentage ramp meaningless while looking healthy — so it must be your decision, visibly.

How it relates

Identity rules

  1. Never auto-generated. A missing targeting key is InvalidContext where the evaluation needs it, never a generated anonymous id.
  2. requireTargetingKey defaults to false on the runtime config where the language exposes it. Set it true if you want keyless calls rejected even in tests.
In-memory evaluation of unconditional fixtures may succeed without a key unless you opt into that strictness.

Two identity paths

These compose; they do not compete.
  1. registerTarget — durable properties stored by fw-server (POST /v1/targets/register). Call once per login or device provisioning.
  2. Per-evaluate attributes — win for that call. Use for request-only facts.
There is no merge step in the SDK. fw-server resolves them: evaluate attributes win; stored target properties fill in everything not sent. A rule that targets a property the app never registers and never sends matches nobody, silently. $-prefixed attributes are backend system directives, not person properties. fw_-prefixed target property keys are reserved and stripped server-side.

Registration in every language

registerTarget exists on all seven SDKs. It never throws — it runs in sign-in paths, where a targeting concern must not break authentication. Check ok. A silently unregistered target is how targeting rules end up matching nobody. The recorded local set is readable (getRegisteredTargets / language equivalent) so tests can assert registration without capturing stdout. The log sink is injectable. The protocol test server implements evaluate, capture, and /health. It does not implement POST /v1/targets/register. Register tests use local mode, mocks, or an injected fetch. Web and Swift also expose identify: register the target, then re-prefetch under that id so percentage ramps bucket on a stable key.

What it looks like

Groups

Group membership and group properties travel on the evaluation context. Canonical keys: fireweave.groups and fireweave.groupProperties. Plain groups / groupProperties are accepted aliases; canonical keys win if both are present. Any other fireweave.* context key is rejected with InvalidContext. targetingKey and kind are also reserved in the evaluation context.

Privacy

  • The SDK adds no person properties of its own. Whatever you put on the context is forwarded to fw-server.
  • Prefer derived attributes (email_domain) over raw PII if you must target on identity-adjacent facts.
  • Error messages are secret-redacted and must not echo attribute values.
  • Nothing is persisted to disk by the SDK.
  • Control points — evaluate with this identity
  • Adapters — remote vs local vs in-memory registration
  • Testing — InMemory does not persist registration; local mode does
Last modified on September 11, 2026