# captureCDR()

Captures the current page and resolves once the evidence has been durably received.

```javascript
const result = await window.ExpressConsent.captureCDR(options);
```

Every option is optional. Called with no arguments it produces a valid record.

## Options

**`custom`** (`object`, optional)

Your own fields, stored with the record and returned as `customMetadata`.

Keys become filterable through the API, primitives directly, array elements under the bare key,
and one level of nesting as `key.subkey`. Matching is exact but case-insensitive and
whitespace-normalized. A single key-and-value pair longer than about 190 characters is not
indexed, and a record indexes at most 250 values in total.

Validate this before you pass it. The limits are enforced when the record is processed rather than
when you call, so an oversized object is not reported back to you.

Constraints: Keys ≤ 100 characters. Values may be primitives, arrays of primitives, or objects one level deep. The whole object must serialize to 16,000 characters or fewer.

**`autoShare`** (`boolean | object`, optional, default `false`)

Generate a share URL during the upload instead of making a second API call. Pass `true` for the
default expiry, or `{ expiresInMs: 604800000 }` to set your own. Read `shareExpiresAt` on the
result for the expiry you actually got.

Constraints: Default expiry 30 days. A request longer than 2 years is clamped rather than rejected; a non-positive value falls back to the default.

**`devMode`** (`boolean`, optional, default `false`)

Create a free, uncollected test CDR that still renders for inspection by members of the producing
organization, including passthrough organizations. The SDK logs concise diagnostics and an
immediate dashboard link that waits for rendering. Remove this option before production.

**`inlineAssets`** (`boolean`, optional, default `false`)

Embed image bytes and `@font-face` fonts in the capture rather than referencing their URLs.
Intended for local development, where our renderer cannot reach `localhost` asset URLs. It
multiplies payload size and can exceed the upload limit, so leave it off in production.

## Result

**`cdrId`** (`string`, required)

The record identifier. Store it with your lead. Its presence is the guarantee that the evidence is
stored.

**`packageData`** (`object`, required)

Session grouping details. `packageId` identifies the managed package for this capture.

**`shareUrl`** (`string`, optional)

The absolute URL to hand to a buyer. Present when `autoShare` is enabled *and* the share token was
created. Token creation is best-effort and its failure does not fail the capture, so check for the
field rather than assuming it, and fall back to the share API if it is absent.

A Dev Mode capture may return this field so you can verify your integration passes it through, but
API and dashboard claim attempts are permanently denied with `CDR_DEV_MODE`.

**`shareToken`** (`string`, optional)

The token from the end of `shareUrl`. Same conditions as above.

**`shareExpiresAt`** (`number`, optional)

Expiry as a Unix timestamp in milliseconds. Same conditions as above.

## Usage

```javascript
form.addEventListener("submit", async (event) => {
  event.preventDefault();
  const phone = form.phone.value;

  try {
    const { cdrId, shareUrl } = await window.ExpressConsent.captureCDR({
      autoShare: true,
      custom: { phone },
    });
    await saveLead({ phone, cdrId, shareUrl });
  } catch (error) {
    console.error("ExpressConsent capture failed", error);
  }

  form.submit();
});
```

`captureCDR()` must be the first thing you `await` in the handler. The capture reads the page at the
moment you call it, so anything you await first is what ends up in the evidence.

If the call resolves, the evidence is stored. That is the guarantee the `cdrId` carries: you never
receive one for a record that was not saved. The visual record renders shortly afterwards, so a record
fetched in the seconds right after a capture may not be readable yet.

## Dev Mode

Use `captureCDR({ devMode: true })` while integrating. The CDR remains `collected: false`, has no API
`downloadUrl`, creates no billing or access-grant records, and cannot be collected or transferred
through API share tokens. It still renders, sends a `cdr.completed` webhook marked `devMode: true`,
and can be reviewed through visibly marked dashboard viewer links and PDFs.

See [Test with Dev Mode](https://expressconsent.com/docs/dev-mode) for the verification workflow.

## Supporting documents

Tag a static privacy policy, terms document, arbitration clause, or PDF that should be archived with
the CDR:

```html
<a
  href="https://example.com/privacy"
  data-ec-supporting-document="privacy-policy"
>
  Privacy Policy
</a>
```

The attribute value is a lowercase identifier of letters, numbers, hyphens, or underscores, and it
names the document on the record. The link's text, and the absolute URL with any fragment removed,
are recorded during the capture. The destination is retrieved afterwards, so this adds no work to
the `captureCDR()` request and does not delay the CDR ID.

If the destination paints its legal text with JavaScript, use `data-ec-supporting-document-render`
instead and we load the page in a browser before archiving it:

```html
<a
  href="https://example.com/terms-conditions/"
  data-ec-supporting-document-render="terms"
>
  Terms &amp; Conditions
</a>
```

The requirements a destination has to meet, and where the archived documents can be read, are on
[Archive linked documents](https://expressconsent.com/docs/tags/supporting-documents).

## Errors

The call rejects rather than returning a partial result. Every error and its cause is on
[SDK errors](https://expressconsent.com/docs/reference/errors). Wrap the call in `try`/`catch` and let the person's
submission proceed regardless.

## Limits

| | |
|---|---|
| Upload size | 3 MiB, measured on the compressed upload rather than the page |
| `custom` serialized size | 16,000 characters |
| `custom` key length | 100 characters |
| Searchable `custom` values | 250 per record, each pair under about 190 characters |
| Disclosures read per page | 50 |
| Disclosure name length | 200 characters |
| Disclosure text stored | 5,000 characters |
| Supporting documents per CDR | 10 |
| Supporting-document HTML | HTTPS, static initial response, maximum 2 MiB |
| Supporting-document PDF | HTTPS, maximum 20 MiB |
