Context
Context is arbitrary runtime data you attach to a form — which course, which screen, which plan tier. It feeds targeting, segments your reporting, and can scope cooldowns so the same form can be asked once per value instead of once per user.
Why it exists
Without context, “How was this course?” needs one form per course. With it, you build one form and tell the SDK which course the user is looking at. Responses arrive tagged, the console segments by that tag, and cooldowns can be kept independent per course.
Two ways to attach it
Sticky context
Merges into a session-scoped bag and stays attached to every show and every response until you clear it or a new session begins.
client.setContext({ courseId: 'c-101', screen: 'lesson' })
// Merges — screen becomes 'quiz', courseId stays 'c-101'
client.setContext({ screen: 'quiz' })
client.setContext(null) // clear it
client.clearContext() // same thingUse it for facts that stay true while the user is somewhere:
// React
'use client'
import { useEffect } from 'react'
import { useSetContext } from '@intunix/react'
export function CoursePage({ courseId }: { courseId: string }) {
const setContext = useSetContext()
useEffect(() => { setContext({ courseId }) }, [courseId, setContext])
// ...
}Per-call context
Scoped to a single showForm() call, and it wins over sticky context for that call.
client.showForm('course_csat', { context: { courseId: 'c-102' } })Allowed values
Context is a flat object of strings, numbers, booleans, and null. No nested objects, no arrays.
// Good
client.setContext({ courseId: 'c-101', lesson: 4, isTrial: false })
// Not supported — nested and array values are rejected
client.setContext({ course: { id: 'c-101' }, tags: ['a', 'b'] })Context is stored with every response and is visible to anyone with console access to that form's results. Use opaque identifiers — courseId, not studentEmail.
Where it flows
| Destination | How it appears |
|---|---|
| Response payloads | As a top-level context object, so the console can segment feedback. |
| Event batches | Attached to each event entry. |
| Targeting | Matched by rules with kind: 'context'. |
| Cadence | Used as the cooldown key when frequencyScope: 'form_context'. |
Targeting on context
// Console config — only ask on the advanced course, and only for trial users
targeting: {
rules: [
{ kind: 'context', key: 'courseId', op: 'eq', value: 'c-101' },
{ kind: 'context', key: 'isTrial', op: 'eq', value: true },
],
}exists is useful for “only ask if we know which course they are on”:
{ kind: 'context', key: 'courseId', op: 'exists' }Per-context cooldowns
Set frequencyScope: 'form_context' on the form and the cadence ledger is keyed by the context values named in its context targeting rules — rather than one entry per user.
// frequencyScope: 'form_context', cadence answered: 90 days
client.showForm('course_csat', { context: { courseId: 'c-101' } })
// → shows, user answers, c-101 now quiet for 90 days
client.showForm('course_csat', { context: { courseId: 'c-101' } })
// → blocked
client.showForm('course_csat', { context: { courseId: 'c-102' } })
// → shows. Different course, independent cooldown.A high-cardinality context key — a session id, a timestamp, a random request id — makes every show a fresh cooldown bucket, which effectively disables cadence and turns the form into a nag. Scope on something a user encounters a handful of times, not thousands.
Reporting
In the console, a form's analytics can be filtered by any context key that has been recorded against it. Responses, score breakdowns, and per-question charts all respect the filter, so you can read NPS for one course, one screen, or one plan tier in isolation.
Context keys are discovered from the data — nothing needs declaring up front. Send a new key and it becomes available as a filter once responses carry it.
Lifecycle
- Sticky context lives in
sessionStorageunderintunix:context. - It is cleared automatically when a new session starts.
- It is cleared by
reset()— see Identity & sessions for why that matters on shared browsers. - Per-call context is consumed by that one show and never persisted.