# 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.

**`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.

**`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.

## 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 containing letters, numbers, hyphens, or underscores.
ExpressConsent records the visible label and absolute URL in the integrity-anchored CDR envelope,
then retrieves the destination asynchronously without cookies. This does not add work to the
`captureCDR()` request and does not delay the CDR ID.

Supporting HTML must contain its readable legal text in the initial HTTP response. ExpressConsent
does not execute JavaScript or use a browser to archive these pages. It removes scripts, forms,
tracking resources, and site styling, then stores a deterministic reader document. PDFs are stored
as exact bytes. Identical reader documents and identical PDFs share one immutable stored artifact
across CDRs.

The CDR states when ExpressConsent retrieved the document. It does not claim that the consumer
opened or read the linked document. Do not place lead identifiers or other personal information in
supporting-document query strings because the complete URL is retained with the record.

## Errors

The call rejects rather than returning a partial result. Every error and its cause is on
[SDK errors](https://app.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 |
