links.arjun.tv/docs/end-user/chain-signals-and-prefetch

Chain Signals and Prefetch

Use this guide to understand how chain signals, rule evaluation, and prefetch work together to enable cross-event personalization.

When to use

  • You want to personalize a visitor's experience based on their behavioral history across multiple page views.
  • You need to understand how signal-based rules differ from static routing rules.
  • You are integrating the chain signals API to drive dynamic content decisions.

Concept overview

Chain signals extend the platform's personalization beyond single-click routing. Instead of deciding the redirect destination at click time only, chain signals let you:

  1. Collect behavioral signals as a visitor interacts with your content.
  2. Accumulate a behavioral profile in a time-windowed signal ledger.
  3. Evaluate rules that react to accumulated signals rather than just current-click context.
  4. Prefetch decisions for multiple trigger events in a single request.

This enables scenarios like: "If the visitor viewed the pricing page and spent 30 seconds on the features page, show the enterprise CTA on their next visit."

Signal model

A signal is a discrete behavioral observation about a visitor within a session:

FieldTypeDescription
signalKeyStringCategory of the observation (e.g., intent, category, conversion)
signalValueString (max 256 chars)Observed value (e.g., rings, pricing-viewed)
confidenceNumber (0.0–1.0)Certainty of the observation
sourceString (optional)Where the signal came from
metadataObject (optional)Additional context (page URL, click ID)

Signals are stored in the Signal Ledger — an append-only, time-windowed DynamoDB table with automatic TTL cleanup.

Session identity

All signals within a session share a sessionId with the format:

sig_{handle}_{timestamp}_{randomId}

A session can accumulate up to 200 signals. Signal write rate is limited to 60 signals per session per minute (120 per IP per minute for public endpoints).

Consent and retention

Consent modeSignal retentionDescription
full30 daysFull cross-session behavioral tracking
basic24 hoursShort-term tracking only
deniedNoneNo signals stored

Chain rules

A chain rule defines when accumulated signals should trigger an action. Rules are evaluated in priority order (lower number = higher priority), and the first match wins.

Rule structure

{
  "ruleId": "early-bird-expired",
  "enabled": true,
  "priority": 100,
  "triggerEvent": "early_bird_deadline",
  "when": {
    "countryIn": ["US", "GB"],
    "deviceIn": ["MOBILE", "DESKTOP"]
  },
  "chainConditions": {
    "require": [
      { "signalKey": "early.bird.deadline", "operator": "equals", "signalValue": "expired" }
    ],
    "exclude": [
      { "signalKey": "already_purchased", "operator": "exists" }
    ],
    "minChainDepth": 1,
    "maxChainAgeMinutes": 1440
  },
  "action": {
    "type": "redirect",
    "destinationUrl": "https://example.com/regular-pricing"
  }
}

Condition operators

OperatorSemanticsExample
existsSignal key has any valueSignal "intent" has been recorded
not_existsSignal key has no valuesNo "conversion" signal yet
equalsExact value match (case-insensitive)Intent equals "rings"
containsSubstring match (case-insensitive)Preference contains "diamond"
count_gteAt least N signals with this keyAt least 2 "category" signals
any_ofValue matches any in a listIntent is "rings" or "watches"

Window scoping

Conditions can optionally be scoped:

ParameterEffect
withinLastNOnly consider the N most recent signals
minConfidenceOnly consider signals with confidence >= threshold

Chain constraints

ParameterEffect
minChainDepthRequire at least N signals in the session
maxChainAgeMinutesReject if the first signal is older than N minutes

Rule evaluation flow

1. Load all enabled rules for handle + triggerEvent
2. Sort by priority (ascending), then by ruleId
3. For each rule:
   a. Check basic conditions (device, country, source, campaign)
   b. Check chain depth constraint
   c. Check chain age constraint
   d. Evaluate ALL "require" conditions (must all match)
   e. Evaluate ALL "exclude" conditions (must all NOT match)
   f. First rule where all checks pass → return its action
4. If no rule matches → return { matched: false }
Step through each gate to see where rules fail fast and when the first matching action is emitted.

Action types

When a rule matches, it returns an action for the client to execute:

Action typeDescription
redirectNavigate visitor to a new URL
show_popupDisplay a popup/modal (client handles rendering)
show_bannerDisplay a banner (client handles rendering)
swap_ctaReplace a CTA element (client handles rendering)
fire_eventTrigger an analytics event
add_to_cartAdd an item to cart (client handles implementation)
no_actionExplicitly do nothing (useful as a catch-all)

Actions support variable interpolation: signal values can be inserted into action fields using {{signalKey}} syntax.

Prefetch

Prefetch lets you pre-compute decisions for multiple trigger events in a single request. This eliminates round-trips when the client needs to know what to do for several possible events.

POST /v2/public/chain/prefetch

{
  "handle": "myhandle",
  "sessionId": "sig_myhandle_1234_abc",
  "triggerEvents": ["exit_intent", "idle_30s", "add_to_cart"],
  "currentContext": {
    "device": "mobile",
    "country": "US",
    "source": "email",
    "pageUrl": "https://example.com/product"
  }
}

Response:

{
  "decisions": {
    "exit_intent": { "matched": true, "ruleId": "offer_popup", "action": { ... } },
    "idle_30s": { "matched": false, "ruleId": null, "action": null },
    "add_to_cart": { "matched": true, "ruleId": "cross_sell", "action": { ... } }
  },
  "validUntil": "2026-02-25T12:35:56.789Z"
}

Prefetch results are cached server-side for 60 seconds per session + trigger event + context hash. Up to 10 trigger events per prefetch request.

Segment token flow

When signals include segment hints (via metadata.intentSegments), the server:

  1. Validates segment labels (regex: ^[a-z0-9][a-z0-9_-]{0,29}$, max 5 segments).
  2. Signs them into an HMAC token.
  3. Returns a segmentToken in the response.
  4. The client stores the token as the lp_seg cookie.

This token is then available to personalization rules that use segmentIn conditions during redirects.

Inspect validation limits and signing behavior before segment tokens are persisted client-side.

Required auth

Public endpoints (no auth required)

EndpointRate limit
POST /v2/public/chain/signals120/IP/min
POST /v2/public/chain/resolve60/IP/min
POST /v2/public/chain/prefetch20/IP/min

Handle-scoped endpoints (JWT or PAT)

EndpointAuthRate limit
POST /v2/handles/{handle}/chain/signalsCREATOR+ or PAT chain.signal.write60/session/min
POST /v2/handles/{handle}/chain/resolveCREATOR+ or PAT chain.resolve.read30/session/min
POST /v2/handles/{handle}/chain/prefetchCREATOR+ or PAT chain.resolve.read10/session/min
GET /v2/handles/{handle}/chain/{sessionId}CREATOR+ or PAT chain.read10/handle/min

Limits

ResourceLimit
Chain rules per handle100
Signals per write request5
Signals per session200
Signal value length256 characters
Trigger events per prefetch10
Decision cache TTL60 seconds

Common errors

CodeErrorCause
400invalid_session_idSession ID does not match expected format
400invalid_signal_keySignal key contains invalid characters
429rate_limitedSignal or resolve rate limit exceeded

Related: