# Axiom

Stream form analytics events and optional full respondent answers into an Axiom dataset.

> ℹ️ **Available on the Free plan.**


## Axiom

Query raw form events in APL, build dashboards and monitors, and optionally send full submitted answers.

<h2 id="connect">Connect Axiom</h2>

<p>
  The two region choices are <strong>US East 1 (AWS)</strong> and <strong>EU Central 1 (AWS)</strong>. Pick the one your Axiom organization
  lives in — formbase derives the ingest endpoint from it, and ingesting into the wrong region is rejected.
</p>

<h2 id="event-stream">Analytics events</h2>

<p>
  Connecting Axiom turns answer-free event forwarding on for every form in the workspace. Records use event names <code>form_view</code>,
  <code>form_engaged</code>, and <code>form_submit</code>, with the same parameters documented in{' '}
  <a href="/integrations/analytics-streaming#event-contract">Analytics streaming</a>.
</p>

<pre>
  <code>{`['your-dataset']
| where ['event'] in ('form_view', 'form_engaged', 'form_submit')
| summarize events=count() by ['event']`}</code>
</pre>

<p>
  Each record flattens the event parameters to top level, so <code>form_id</code>, <code>source</code>, <code>device</code> and the rest are
  ordinary columns you can filter and summarize on.
</p>

<p>
  Event forwarding is best-effort and not retried. Disable it for one form under{' '}
  <strong>Form settings → Integrations → Analytics streaming → Forward analytics events</strong>.
</p>

<h2 id="answers">Respondent answers</h2>

<p>
  Axiom can also receive one full record per completed submission. This stream is <strong>off by default</strong> and must be enabled
  separately for each form with <strong>Send respondent answers</strong>.
</p>

<p>
  An answer record is the same event envelope a <a href="/integrations/webhooks">custom webhook</a> receives, plus an Axiom{' '}
  <code>_time</code> field: the event id, type, <code>createdAt</code>, <code>apiVersion</code> and <code>test</code>, and under{' '}
  <code>data</code> the form, the submission (id, respondent email, submitted time, PDF link, language), an <code>answers</code> object
  keyed by <a href="/requests/field-keys">field key</a> and a <code>display</code> object with the same keys as readable text. Submissions
  that answered a request also carry a <code>request</code> block with your external id and metadata. The full shape is in the{' '}
  <a href="/developers/webhooks-reference#payload">webhook reference</a>.
</p>

<p>
  Answers are streamed when a submission is completed and again when a respondent edits it. Abandoned drafts never reach Axiom this way —
  answer streaming has no idle window.
</p>

> ⚠️ **Answer records contain personal data**
> <p>
>     A full submission can contain names, emails, free text, files, signatures, and other sensitive answers. Use a restricted dataset, keep
>     token scope narrow, and set retention/access rules before enabling this stream.
>   </p>

<h2 id="delivery">Answer delivery and failures</h2>

<p>
  Answer records ride the submission delivery queue: up to 5 attempts with exponential backoff. After 20 consecutive failures the
  destination stops being queued, so a bad token or a rejected dataset cannot generate a failing delivery for every new submission. Saving a
  new API token clears the error and resumes delivery.
</p>

<p>
  Event forwarding and answer streaming have independent switches. You can send answers without events, events without answers, both, or
  neither for each form.
</p>

<h2 id="troubleshooting">Troubleshooting</h2>

<h2 id="next-steps">Next steps</h2>

<div class="not-prose grid gap-3 sm:grid-cols-2">
  - [Analytics streaming](/integrations/analytics-streaming) — Shared schema, defaults, and privacy
  - [Integration health](/integrations/health-monitoring) — Understand retries and auto-pause
</div>
