> ## Documentation Index
> Fetch the complete documentation index at: https://docs.os.default.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Understand the Pixel and Forms SDK

> Learn how the Pixel and Forms SDK handle identity, submissions, workflows, and scheduler handoffs.

Use this guide to understand how Default processes a visitor from page load to scheduler handoff.

You will also learn why late initialization delays identity lookup and can prevent the scheduler
from appearing.

For domain setup, form approval, and field mapping, follow
[Set up the Pixel and Forms SDK](/pixel-sdk-setup).

Use the [API reference](/pixel-sdk-reference) when you need an exact option, method, or event.

## Two scripts, one identity

Default ships two browser scripts. You can load one or both on the same page.

Both scripts share the same visitor identity and session. Loading both never double-counts a
visitor or resets who they are.

| Script                   | Global                   | What it's for                                                                                                                                                                              |
| ------------------------ | ------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| The Pixel (`index.js`)   | `window.DefaultPixel`    | Detects on its own which form was submitted, what a visitor typed, and when they viewed a page. You write no code beyond the install snippet.                                              |
| The Forms SDK (`sdk.js`) | `window.DefaultPixelSDK` | A programmatic API you call yourself to report a submission and its values. Use it for custom-built forms (React, Vue, a multi-step flow), or for explicit control over what happens next. |

Most sites only need the Pixel. Use the SDK in these cases:

* Your form is not a plain HTML `<form>` element.
* You want to control exactly how, or whether, the scheduler appears after submission.

See [API reference](/pixel-sdk-reference) for the full method and configuration list for each.

## How it works, end to end

1. The script loads and initializes. It runs as soon as the page is ready, or immediately if the
   page already finished loading.
2. The script establishes identity and session. It sets a long-lived anonymous visitor id, starts a
   30-minute rolling session, and records the page view.
3. The script fetches the list of forms wired to a scheduling workflow. It does this once at
   startup, before the visitor gets near the submit button.
4. Pre-enrichment starts while the visitor fills out a tracked form. The moment they finish typing
   their email and move to the next field, the script sends what they entered so far to Default.
5. If Default recognizes the email, it identifies the company and person in the background. It also
   checks your CRM for a matching record, before the visitor clicks submit.
6. The visitor submits. The script, or your code if you use the SDK, sends the full responses to
   Default with the pre-enrichment and CRM match results that are ready by then.
7. Any workflow attached to that form runs. Routing, scoring, enrichment, and scheduling all happen
   in Default, exactly as configured in your workspace.
8. The workflow hands back the next action:
   * Nothing. The page shows its own thank-you state.
   * A redirect to a specific URL.
   * A scheduler handoff. The script shows the booking calendar
     (see [The scheduler experience](#the-scheduler-experience)).

Steps 3 to 5 go wrong when you install the script late. See
[Initialize on page load, not at submit](#initialize-on-page-load-not-at-submit) below.

## Install

### The snippet

<Frame>
  <img src="https://mintcdn.com/default-b6d0c477/39YvaBpPGQDPEJa1/images/forms/pixel-install-snippet.png?fit=max&auto=format&n=39YvaBpPGQDPEJa1&q=85&s=90acb4ef21b908546fc133517b1d5e83" alt="The Pixel install snippet for a connected domain in Default" width="2880" height="1800" data-path="images/forms/pixel-install-snippet.png" />
</Frame>

<Steps>
  <Step title="Copy your snippet">
    Open **Settings** → **Configurations** → **Pixel** → **Domains** and copy the snippet. It comes with
    your domain's public key already filled in.

    If your workspace shows a **Forms** app, **Forms** → **Domains** → **Copy Pixel script** gives the
    same snippet. If your navigation is a sidebar in place of the **Dock**, the sidebar labels that
    same page **Signals**.

    The snippet looks like this:

    ```html theme={null}
    <!-- Default Pixel -->
    <script>
      window.__defaultPixel__ = { key: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" };
    </script>
    <script async src="https://pixel.default.com/index.js"></script>
    ```
  </Step>

  <Step title="Add the SDK script if you use it">
    To load the programmatic SDK on the same page, load it the same way with `sdk.js` in place of
    `index.js`. Both scripts read the same `window.__defaultPixel__.key`.

    ```html theme={null}
    <script async src="https://pixel.default.com/sdk.js"></script>
    ```
  </Step>
</Steps>

The `key` value is a public key. It belongs in client-side code, so you do not have to hide or
proxy it.

### Where it goes

Put the snippet in the `<head>` of every page you want tracked.

* Add it to your site-wide template or layout. You then do not have to add it page by page.
* A tag manager also works. Use a custom HTML tag that fires on all pages.
* Single-page apps need the snippet only once. The script detects client-side route changes on its
  own and re-evaluates each new "page" without a reload.

<Warning>
  Do not add the script tag conditionally. Do not defer creating it until a form's submit handler.

  The next section explains exactly what that breaks.
</Warning>

## Initialize on page load, not at submit

This is the most common integration mistake we see. It is worth understanding *why* it matters, not
just that it does.

Some things happen correctly only when the script runs from the moment the page loads:

#### 1. Pre-enrichment and CRM matching lose their early start

The script starts to identify a visitor the moment they leave the email field, well before submit.
It also starts to check your CRM then.

This works only when the script's interaction listeners were attached before the visitor typed
their email. If the script, `DefaultPixelSDK.init()`, or the visitor's `<form>` shows up later,
nothing catches that moment.

The submission still goes through. But Default must then do the identification and CRM lookup after
submit, which adds real time between "submit" and "here's your calendar."

#### 2. The scheduler-enabled forms list may not have loaded yet

Right after it starts, the script fetches the list of forms on the page wired to a scheduling
workflow. It then knows in advance to intercept those forms' native submit behavior and show the
calendar instead.

Interception stops the browser from navigating to the form's plain `action` URL. If the script only
starts at submit time, that fetch has possibly not finished.

In the worst case, the browser follows the form's default action. The visitor never reaches the
calendar at all.

#### 3. Identity resolution needs a moment to run

The stable anonymous visitor id takes a moment to generate. A submission that fires in the very
first instant of the script's life may fall back to a temporary id for that one event.

All three point at the same fix:

<CodeGroup>
  ```html correct.html theme={null}
  <!-- In <head>, present on every page load -->
  <script>
    window.__defaultPixel__ = { key: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" };
  </script>
  <script async src="https://pixel.default.com/index.js"></script>
  ```

  ```html wrong.html theme={null}
  <!-- Don't do this: script only appears once the visitor is already submitting -->
  <form id="demo-form" onsubmit="loadPixelScriptThenSubmit()">
    ...
  </form>
  ```
</CodeGroup>

The visible symptom is exactly what it sounds like. Booking slots take a noticeably long time to
appear after the visitor submits, or the calendar never appears at all.

The fix is always the same. Load and initialize the script, or call `DefaultPixelSDK.init()`, on
page load.

Do not do this inside a submit handler. Do not put it behind a condition that delays it past the
visitor's first interaction with the form.

The same rule applies when you call `recordFormInteraction()` yourself to mirror the email-blur
warmup (see [Form binding](#form-binding) below). Call it as soon as the visitor supplies their
email, not at submit time.

## Form binding

### Automatic detection (the Pixel)

Once running, the Pixel recognizes forms on its own. That includes forms added to the page after
load, for example inside a modal or after a client-side route change:

* Plain HTML forms: any `<form>` element that does not match one of the vendor patterns below. The
  script listens for its `submit` event and for focus, blur, and change activity on its fields.
* HubSpot forms: the script recognizes a form id that starts with `hsForm_`, a `hs-form` class, an
  `hs_context` hidden field, or an action that points at HubSpot's form domains. It also recognizes
  HubSpot's newer embed through that embed's own ready and submission events.
* Marketo forms: the script detects these through Marketo's own form-ready API.
* Paperform embeds: the script detects these through Paperform's own submission messages.

The script also picks up forms in a same-origin iframe, one it can read into. It cannot read into a
cross-origin iframe, for example a landing-page builder hosted on someone else's domain.

If you control that cross-origin iframe's content, add the install snippet inside it directly.

### Manual submission (the SDK)

For a form the Pixel cannot detect cleanly, call the SDK directly instead. A fully custom React or
Vue form is a typical case:

```ts theme={null}
const result = await DefaultPixelSDK.submitForm({
  pixelFormId: "your_pixel_form_id", // the id Default assigned when you approved the form
  responses: {
    email: "jordan@acme.com",
    first_name: "Jordan",
    company_domain: "acme.com",
  },
});
```

See [submitForm](/pixel-sdk-reference#submitform) in the reference for the full option list and
return shape.

Your workspace's form editor also ships a working code sample for this exact call. Open **Forms**,
select a form, then open its **Install** tab, section **Use the SDK**.

The sample comes pre-filled with your real public key, form id, and field names. Split it apart
rather than paste it as one block.

Keep the `init()` call and script tag on page load, exactly as shown, per
[Initialize on page load, not at submit](#initialize-on-page-load-not-at-submit) above. Move the
`submitForm()` call to wherever your own code actually collects a submission.

As pasted, the sample calls both immediately. That confirms the connection works, but it is not a
real integration.

The neighboring **Test** tab fires real test submissions and pre-enrichment against your fields.
You do not have to leave the editor.

If your custom form's fields are not inside a native `<form>` element, the automatic email-blur
warmup that powers pre-enrichment has nothing to attach to. Call `recordFormInteraction()` yourself
as soon as the visitor leaves the email field, so pre-enrichment still gets its early start:

```ts theme={null}
document.getElementById("email-field").addEventListener("blur", (e) => {
  DefaultPixelSDK.recordFormInteraction({
    formId: "request-demo", // the HTML form id, not the Pixel form UUID
    fieldName: "email",
    fieldValue: e.target.value,
  });
});
```

Pass that same HTML form ID as `submitForm({ formId })`. Pass Default's form UUID separately as
`submitForm({ pixelFormId })`.

See [recordFormInteraction](/pixel-sdk-reference#recordforminteraction) for the full signature.

### Excluding a page or a form from capture

* Turn off capture for an entire page with a meta tag in that page's `<head>`:
  ```html theme={null}
  <meta name="default:pixel" content="noform">
  ```
* The script skips sensitive paths automatically: `/login`, `/signin`, `/account`, `/checkout`,
  `/oauth`, and any path under `/admin/`.
* To exclude one form without opting out the whole page, add a `data-default-ignore` attribute to
  that form or to any element that wraps it:
  ```html theme={null}
  <form id="internal-tool-form" data-default-ignore>
    ...
  </form>
  ```

## The scheduler experience

The Pixel and the SDK both show the booking calendar the same way. It is a full-screen overlay
on top of your page.

The calendar renders its own dimmed backdrop and card. It reads as a modal without a second
frame around it.

Before the calendar itself is ready, a branded loading indicator appears first. It uses your
workspace's scheduler colors and logo, if you set them.

A short rotating message tells the visitor that something is happening. Once the calendar is ready,
it replaces the indicator in a single swap, with no blank flash in between.

If the visitor's pre-enrichment and CRM matching already ran early (see above), this handoff is
fast. If the script had to do that work after submit, the visitor sits in this loading state
longer.

The `autoDisplayScheduler` option controls the display mode. Set it on `DefaultPixelSDK.init()` or
in the `window.__defaultPixel__` block, which both scripts read.

You can also override it per call to `DefaultPixelSDK.submitForm()`:

* Modal (default): the full-screen overlay described above. Nothing to configure.
* Inline: the calendar mounts into a container element you specify, so it feels like part of your
  page. Add `loader: true` to also show the branded loading indicator in that container while the
  calendar loads.
  ```ts theme={null}
  await DefaultPixelSDK.submitForm({
    pixelFormId,
    responses,
    autoDisplayScheduler: { target: "#meeting-section", loader: true },
  });
  ```
* Off: the script displays nothing, and you read the URL off the result yourself. This mode only
  exists for `submitForm()`.
  ```ts theme={null}
  const result = await DefaultPixelSDK.submitForm({ pixelFormId, responses, autoDisplayScheduler: false });
  if (result.scheduler) {
    window.location.href = result.scheduler.url;
  }
  ```

A plain HTML form the Pixel auto-detects can render inline too, with no SDK call involved. Set
`window.__defaultPixel__.autoDisplayScheduler = { target: "#meeting-section" }` in your install
snippet, and the Pixel mounts the calendar there on a scheduler handoff.

An auto-detected form cannot turn display off. The `true`/`false` shape of `autoDisplayScheduler`
only affects `submitForm()`.

On a scheduler handoff, an auto-detected form always shows the calendar somewhere, full-screen or
in your target container. There is no calling code for the Pixel to hand a suppressed URL back to.

A calendar you displayed through `submitForm()` closes itself in these cases:

* The visitor books or cancels.
* The booking session times out.
* A workflow is configured to redirect afterward.

On an auto-detected form, the calendar closes when it reports itself closed, on `Escape`, or if it
fails to load. If you need it to come down on any other signal, subscribe to the event and close it
yourself.

You can close it at any time on either path with:

```js theme={null}
window.postMessage("__default_scheduler_close__:re:null", "*");
```

For the full event list you can subscribe to (booked, cancelled, closed, and so on), see
[Scheduler events](/pixel-sdk-reference#scheduler-events) in the reference. Subscribing works the
same way from either script, with `DefaultPixel.on(...)` or `DefaultPixelSDK.on(...)`.

You do not need the SDK on the page just to listen for scheduler events.

## Troubleshooting

| Symptom                                                                                                      | Likely cause                                                                                                                                                                                                                                 | Fix                                                                                                                                                                         |
| ------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Booking slots take a long time to appear after submit, or the calendar feels laggy                           | The script initialized late, for example inside a submit handler. Pre-enrichment and CRM matching then run after submit instead of early.                                                                                                    | Initialize on page load, in the `<head>`. See [Initialize on page load, not at submit](#initialize-on-page-load-not-at-submit)                                              |
| The browser navigates to the form's plain action URL instead of showing the calendar                         | Same root cause. The script had not yet learned this form was wired to a scheduling workflow.                                                                                                                                                | Same fix: initialize on page load                                                                                                                                           |
| A form does not show up as detected, or submissions do not come through                                      | Check, in order: a `<meta name="default:pixel" content="noform">` tag, a `data-default-ignore` attribute on the form or an ancestor, a sensitive path like `/login` or `/checkout`, a cross-origin iframe, or a missing snippet on that page | Remove an unintended meta tag or attribute, and confirm the snippet is on the page you test. If the form lives in an iframe, add the snippet inside that iframe's own page. |
| A HubSpot, Marketo, or Paperform form is not detected even though it is the right vendor                     | The embed does not match that vendor's standard markup or script, for example a heavily customized or self-hosted embed                                                                                                                      | Confirm the embed uses the vendor's standard script and markup. Or submit explicitly with `DefaultPixelSDK.submitForm()`.                                                   |
| A Pardot form's submissions never arrive                                                                     | Automatic detection does not capture Pardot forms today                                                                                                                                                                                      | Submit explicitly with `DefaultPixelSDK.submitForm()`. It works regardless of the form's vendor.                                                                            |
| The very first submission on a page looks like a brand-new anonymous visitor, even for a returning one       | Identity resolution had not finished yet, most likely because the script only started at submit time                                                                                                                                         | Initialize on page load. Identity then has time to resolve before any real interaction.                                                                                     |
| The calendar never appears, or the console shows a warning about an invalid scheduler URL                    | The URL from the workflow failed the script's safety check. The script only ever renders your Default domain, over HTTPS.                                                                                                                    | Turn on verbose logging (below) to see the exact URL and warning. Then check the workflow's Display Scheduler step.                                                         |
| `submitForm()` resolves with `success: false`                                                                | A 404 status means the form id does not belong to the domain tied to your public key. Other non-2xx statuses are network or server errors.                                                                                                   | Check `result.status` and `result.error`. Confirm the form id and domain match, then retry or fall back to your own confirmation flow.                                      |
| `submitForm({ pixelFormId })` submits against the wrong form (or none) on a page with more than one `<form>` | With only a `pixelFormId`, the SDK guesses which DOM form you mean: the currently focused field's form, or a form tagged with a matching `data-pixel-form-id`                                                                                | Also pass `formId`, the form's HTML id. Or add a `data-pixel-form-id` attribute that matches the id you submit against.                                                     |
| You need more visibility into what the script does on a page                                                 | Debug logging is silent by default                                                                                                                                                                                                           | Set `window.__defaultPixel__logging__verbose = true` before the script loads, then reload and check the console. Every step logs a `[Default.com]`-prefixed line.           |

## Next steps

<CardGroup cols={2}>
  <Card title="Set up the Pixel and Forms SDK" icon="images" href="/pixel-sdk-setup">
    Connect a domain, approve a form, install the SDK, and verify a workflow.
  </Card>

  <Card title="Build a reliable Forms SDK flow" icon="shield-check" href="/pixel-sdk-best-practices">
    Apply the recommended initialization, submission, and scheduler pattern.
  </Card>

  <Card title="Use the API reference" icon="sliders" href="/pixel-sdk-reference">
    Find every configuration option, method, return value, and scheduler event.
  </Card>
</CardGroup>
