---
title: lead-capture
description: >-
  The lead-capture feature enables merchants to capture leads on their
  storefront by recognizing returning Shop users and facilitating email
  collection.
source_url:
  html: 'https://shopify.dev/docs/api/shop-sdk/reference/lead-capture'
  md: 'https://shopify.dev/docs/api/shop-sdk/reference/lead-capture.md'
api_name: shop-sdk
---

# lead-capture

The `lead-capture` feature enables merchants to capture leads on their storefront by recognizing returning [Shop](https://shop.app) users and facilitating email collection.

It supports two main flows:

* **Discount flow**: Offer a discount code in exchange for an email, using the `onAuthenticate` callback.
* **Default flow**: Standard email capture without a discount incentive.

The feature detects whether the current visitor is a known Shop user and can display a call-to-action button (for example, "Continue with Shop") or integrate inline with an existing email input field.

***

## Usage

Create a lead-capture instance via the SDK:

```javascript
const sdk = window.ShopSDK.initialize({
  apiKey: 'YOUR_CLIENT_ID',
});


const leadCapture = await sdk.create('lead-capture', {
  attributes: {
    emailInputSelector: '#email',
  },
  onComplete(event) {
    console.log('Lead captured:', event.email);
  },
});


document.querySelector('#lead-capture-mount').appendChild(leadCapture.element);
```

You can also eagerly preload the feature loader before calling `create`:

```javascript
const sdk = window.ShopSDK.initialize({
  apiKey: 'YOUR_CLIENT_ID',
  features: { 'lead-capture': true },
});
```

#### LeadCaptureConfig

Config accepted by `sdk.create('lead-capture', config)`.

Derived from `LeadCaptureRegistrationSpec`: includes all component attributes, all event handlers, plus SDK-specific fields like `appearance`.

* **appearance**

  **AppearanceConfig**

  Component-level appearance overrides. Variables set here take precedence over those set in `initialize` or `update()`.

* **attributes**

  **LeadCaptureAttributes**

  Component attributes. These map to HTML attributes on the underlying `<shop-lead-capture>` element.

* **id**

  **string**

  Consumer-provided identifier used to route redirect completion back to the same instance that started the flow.

* **on​Authenticate**

  **() => Promise<{ discount: LeadCaptureDiscount; }>**

  Fired during the discount flow to retrieve the discount to offer.

* **on​Before​Authenticate**

  **() => void | Promise\<void>**

  Fired before authentication begins. Can be async.

* **on​Complete**

  **(event: LeadCaptureCompleteEvent) => void**

  Fired when the lead capture flow completes successfully.

* **on​Confirm​Success**

  **() => void**

  Fired after the user confirms a successful action.

* **on​Error**

  **(event: LeadCaptureErrorEvent) => void**

  Fired when an error occurs during the flow.

* **on​Get​Email​Input**

  **() => HTMLInputElement**

  Fired to retrieve the email input element (alternative to emailInputSelector).

* **on​Load**

  **(event: LeadCaptureLoadEvent) => void**

  Fired when the component loads and user recognition completes.

* **on​Ready**

  **(event: ReadyEvent) => void**

  SDK-level ready handler (fires when the element's loader resolves).

* **on​Restart**

  **() => void**

  Fired when the user restarts the flow.

### AppearanceConfig

Appearance configuration for styling Shop SDK components. Set at the instance level in \`initialize()\` or per-feature in \`create()\`.

* preferredLoginExperience

  Preferred UX for the login experience: \`'redirect'\`, \`'popup'\`, or \`null\` for the default.

  ```ts
  'redirect' | 'popup' | null
  ```

* variables

  CSS custom property overrides.

  ```ts
  AppearanceVariables
  ```

### AppearanceVariables

CSS custom properties that control styling of Shop SDK components. All properties are optional — only set ones will be applied.

* \--buttons-radius

  Border radius for buttons (e.g. \`'12px'\`).

  ```ts
  string
  ```

* \--font-paragraph--line-height

  Line height for paragraph text (e.g. \`'22px'\`).

  ```ts
  string
  ```

* \--font-paragraph--size

  Font size for paragraph text (e.g. \`'16px'\`).

  ```ts
  string
  ```

* \--shop-pay-button-border-radius

  Border radius of the Shop Pay button (e.g. \`'4px'\`, \`'999px'\`).

  ```ts
  string
  ```

* \--shop-pay-button-height

  Height of the Shop Pay button (e.g. \`'48px'\`).

  ```ts
  string
  ```

* \--shop-pay-button-padding-block

  Top and bottom padding of the Shop Pay button (minimum \`'8px'\`, default \`'16px'\`).

  ```ts
  string
  ```

* \--shop-pay-button-width

  Width of the Shop Pay button (e.g. \`'260px'\`, \`'100%'\`).

  ```ts
  string
  ```

* \--x-spacing-base

  Base spacing unit (e.g. \`'14px'\`).

  ```ts
  string
  ```

* \[variable: \`--${string}\`]

  ```ts
  string | undefined
  ```

### LeadCaptureAttributes

Attributes accepted by the \`lead-capture\` feature.

* apiKey

  Secondary client ID. If supplied, the client ID will receive a delegated consent token on behalf of the primary client ID.

  ```ts
  string
  ```

* authorizationDetails

  RAR \`authorization\_details\` (a JSON string) requesting data sharing at the consent step. Each entry carries a \`type\`; for Lead Capture that is \`urn:shopify:shop\_app:data-sharing:v1\`, whose \`datatypes\` name the fields requested — \`given\_name\`, \`family\_name\`, \`phone\_number\`, \`birthdate\`. Forwarded verbatim on every authorization request. If it is not well-formed JSON, or the resulting authorization request would exceed the maximum URL length, authentication is aborted with an error rather than sent with the value dropped.

  ```ts
  string
  ```

* buttonLayout

  Layout style for the button: \`'or'\` or \`'standalone'\`.

  ```ts
  LeadCaptureButtonLayout
  ```

* buttonType

  Type of CTA button shown when a Shop user is recognized.

  ```ts
  LeadCaptureButtonType
  ```

* clientId

  Primary Client ID. This client will be shown to the buyer in the sign in flow and is the Relying Party of the OAuth flow. If omitted, defaults to the Shopify Merchant.

  ```ts
  string
  ```

* devMode

  Enable development mode for testing.

  ```ts
  boolean
  ```

* disclosureScope

  Additional disclosure scopes requiring explicit consent.

  ```ts
  string
  ```

* disclosureText

  Custom disclosure text shown during the consent step.

  ```ts
  string
  ```

* disclosureTitle

  Custom title for the disclosure consent screen.

  ```ts
  string
  ```

* emailInputSelector

  CSS selector for the email input on the page.

  ```ts
  string
  ```

* phoneCapture

  Enable phone number capture.

  ```ts
  boolean
  ```

* phoneCaptureDisclosureText

  Disclosure text shown when requesting the user's phone number.

  ```ts
  string
  ```

* presentationMode

  Control the presentation mode where relevant, such for recognised users.

  ```ts
  PresentationMode
  ```

* returnTo

  Where the buyer returns after completing the flow. Defaults to \`'index'\`.

  ```ts
  LeadCaptureReturnTo
  ```

* scope

  Space-separated list of OAuth scopes.

  ```ts
  string
  ```

* storefrontOrigin

  Origin of the embedding storefront.

  ```ts
  string
  ```

* uxMode

  UX mode for the auth flow: \`'iframe'\`, \`'windoid'\`, or \`'redirect'\`.

  ```ts
  'iframe' | 'windoid' | 'redirect'
  ```

### LeadCaptureButtonLayout

Layout style for the lead capture button. - \`'or'\` — Shows an “or” separator between the button and the form. - \`'standalone'\` — Shows the button without any separator.

```ts
'or' | 'standalone'
```

### LeadCaptureButtonType

The type of call-to-action button shown when a Shop user is recognized. - \`'none'\` — No button; uses inline email-based flow instead. - \`'claim'\` — Shows “Claim with Shop” button. - \`'continue'\` — Shows “Continue with Shop” button. - \`'notify'\` — Shows “Notify me with Shop” button. - \`'save'\` — Shows “Save with Shop” button.

```ts
'none' | 'claim' | 'continue' | 'notify' | 'save'
```

### LeadCaptureReturnTo

Where the buyer returns after completing the flow. - \`'index'\` — Returns to the storefront home page. - \`'same-page'\` — Returns to the storefront path where the flow started.

```ts
'index' | 'same-page'
```

### LeadCaptureDiscount

A discount to apply after successful lead capture.

* code

  The discount code string.

  ```ts
  string
  ```

* gid

  The Shopify global ID of the discount, if available.

  ```ts
  string
  ```

### LeadCaptureCompleteEvent

Event payload dispatched when the lead capture flow completes.

* consentedScopes

  A space-separated list of OAuth scopes the user consented to.

  ```ts
  string
  ```

* customerAccessToken

  A customer access token issued after authentication, if available.

  ```ts
  string
  ```

* customerAccessTokenExpiresAt

  ISO 8601 timestamp of when the customer access token expires.

  ```ts
  string
  ```

* customerUpdateErrors

  Error messages from the customer update mutation, if any.

  ```ts
  string
  ```

* declined

  Whether the user declined a sign-in or consent step during the flow.

  ```ts
  boolean
  ```

* disclosureAgreed

  Whether the user agreed to the disclosure presented during the flow.

  ```ts
  boolean
  ```

* email

  The email address captured from the user.

  ```ts
  string
  ```

* emailVerified

  Whether the user's email has been verified.

  ```ts
  boolean
  ```

* phoneShareConsent

  Whether the user consented to share their phone number.

  ```ts
  boolean
  ```

* shopConsentToken

  A token that can be exchanged in the Shop Partners API to receive access for a user in the Shop Users API

  ```ts
  string
  ```

* signedIn

  Whether the user signed in during the flow (as opposed to only providing their email).

  ```ts
  boolean
  ```

### LeadCaptureErrorEvent

Event payload dispatched when an error occurs during lead capture.

* code

  A machine-readable error code.

  ```ts
  string
  ```

* email

  The email address associated with the error, if available.

  ```ts
  string
  ```

* message

  A human-readable error message.

  ```ts
  string
  ```

### LeadCaptureLoadEvent

Event payload dispatched when the lead capture component finishes loading.

* userFound

  Whether a recognized Shop user was detected for the current browser session.

  ```ts
  boolean
  ```

### ReadyEvent

Event payload passed to the \`onReady\` handler when a feature element finishes loading.

* detail

  Underlying \`CustomEvent.detail\` from the element's \`'loaded'\` event, when available. Shape is feature-specific — e.g. for lead-capture this includes fields like \`userFound\`, \`loginTitle\`, etc. emitted by \`useAuthorizeEventListener\`.

  ```ts
  unknown
  ```

* elementTagName

  Tag name of the element that became ready, e.g. \`shop-lead-capture\`.

  ```ts
  string
  ```

#### LeadCaptureInstance

Runtime instance returned by `sdk.create('lead-capture')`.

Exposes:

* All component methods from the registration spec
* `setAttribute` for updating attributes after creation
* Event subscription methods for each event handler
* `onReady` with late-subscriber semantics
* `element` for DOM insertion
* `destroy` for cleanup

- **destroy**

  **() => void**

  **required**

  Tear down listeners and remove the element from the DOM if attached.

- **element**

  **HTMLElement**

  **required**

  The underlying custom element. The consumer is responsible for inserting it into the DOM.

- **notify​Email​Field​Shown**

  **() => void**

  **required**

  Notify the component that the email field has been shown.

- **on​Authenticate**

  **(handler: () => Promise<{ discount: LeadCaptureDiscount; }>) => void**

  **required**

  Register an `onAuthenticate` handler.

- **on​Before​Authenticate**

  **(handler: () => void | Promise\<void>) => void**

  **required**

  Register an `onBeforeAuthenticate` handler.

- **on​Complete**

  **(handler: (event: LeadCaptureCompleteEvent) => void) => void**

  **required**

  Register an `onComplete` handler.

- **on​Confirm​Success**

  **(handler: () => void) => void**

  **required**

  Register an `onConfirmSuccess` handler.

- **on​Error**

  **(handler: (event: LeadCaptureErrorEvent) => void) => void**

  **required**

  Register an `onError` handler.

- **on​Load**

  **(handler: (event: LeadCaptureLoadEvent) => void) => void**

  **required**

  Register an `onLoad` handler.

- **on​Ready**

  **(handler: (event: ReadyEvent) => void) => void**

  **required**

  Register an `onReady` handler. Fires immediately if already ready.

- **on​Restart**

  **(handler: () => void) => void**

  **required**

  Register an `onRestart` handler.

- **set​Attribute**

  **(attrs: Partial\<LeadCaptureAttributes>) => void**

  **required**

  Update one or more attributes on the underlying element. Accepts the same attribute keys as `config.attributes`.

- **start**

  **(email?: string) => void**

  **required**

  Trigger the lead-capture flow, optionally with a pre-filled email.

#### LeadCaptureCompleteEvent

Event payload dispatched when the lead capture flow completes.

* **email**

  **string**

  **required**

  The email address captured from the user.

* **signed​In**

  **boolean**

  **required**

  Whether the user signed in during the flow (as opposed to only providing their email).

* **consented​Scopes**

  **string**

  A space-separated list of OAuth scopes the user consented to.

* **customer​Access​Token**

  **string**

  A customer access token issued after authentication, if available.

* **customer​Access​Token​Expires​At**

  **string**

  ISO 8601 timestamp of when the customer access token expires.

* **customer​Update​Errors**

  **string**

  Error messages from the customer update mutation, if any.

* **declined**

  **boolean**

  Whether the user declined a sign-in or consent step during the flow.

* **disclosure​Agreed**

  **boolean**

  Whether the user agreed to the disclosure presented during the flow.

* **email​Verified**

  **boolean**

  Whether the user's email has been verified.

* **phone​Share​Consent**

  **boolean**

  Whether the user consented to share their phone number.

* **shop​Consent​Token**

  **string**

  A token that can be exchanged in the Shop Partners API to receive access for a user in the Shop Users API

#### LeadCaptureErrorEvent

Event payload dispatched when an error occurs during lead capture.

* **code**

  **string**

  **required**

  A machine-readable error code.

* **message**

  **string**

  **required**

  A human-readable error message.

* **email**

  **string**

  The email address associated with the error, if available.

#### LeadCaptureLoadEvent

Event payload dispatched when the lead capture component finishes loading.

* **user​Found**

  **boolean**

  **required**

  Whether a recognized Shop user was detected for the current browser session.

### Examples

* #### Basic usage

  ##### Description

  Create a lead-capture instance with an email input and handle the complete event.

  ##### HTML

  ```html
  <script type="module">
    import 'https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.sdk.esm.js';

    const sdk = window.ShopSDK.initialize({
      apiKey: 'YOUR_CLIENT_ID',
      locale: 'en',
    });

    const leadCapture = await sdk.create('lead-capture', {
      attributes: {
        emailInputSelector: '#email',
      },
      onComplete(event) {
        console.log('Lead captured:', event.email);
      },
    });

    document.querySelector('#lead-capture-mount').appendChild(leadCapture.element);
  </script>

  <form id="lead-capture-form">
    <label for="email">Email address</label>
    <input type="email" id="email" name="email" placeholder="Enter your email" />
  </form>

  <div id="lead-capture-mount"></div>
  ```

* #### Discount flow

  ##### Description

  Offer a discount code to users who provide their email via the \`onAuthenticate\` callback.

  ##### HTML

  ```html
  <script type="module">
    import 'https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.sdk.esm.js';

    const sdk = window.ShopSDK.initialize({
      apiKey: 'YOUR_CLIENT_ID',
      locale: 'en',
      onError(event) {
        console.error('[ShopSDK]', event.message, event.cause);
      },
    });

    const leadCapture = await sdk.create('lead-capture', {
      attributes: {
        emailInputSelector: '#newsletter-email',
        flow: 'discount',
      },
      onAuthenticate: async () => {
        return { discount: { code: 'WELCOME10' } };
      },
      onComplete(event) {
        console.log('Lead captured:', event.email);
        console.log('Signed in:', event.signedIn);
      },
      onLoad(event) {
        if (event.userFound) {
          console.log('Recognized Shop user detected');
        }
      },
    });

    document.querySelector('#lead-capture-mount').appendChild(leadCapture.element);
  </script>

  <form id="newsletter-form">
    <label for="newsletter-email">Get 10% off your first order</label>
    <input
      type="email"
      id="newsletter-email"
      name="email"
      placeholder="Enter your email"
    />
    <button type="submit">Subscribe</button>
  </form>

  <div id="lead-capture-mount"></div>
  ```

* #### Button flow

  ##### Description

  Show a "Continue with Shop" button for recognized users instead of an inline email input.

  ##### HTML

  ```html
  <script type="module">
    import 'https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.sdk.esm.js';

    const sdk = window.ShopSDK.initialize({
      apiKey: 'YOUR_CLIENT_ID',
      locale: 'en',
    });

    const leadCapture = await sdk.create('lead-capture', {
      attributes: {
        buttonType: 'continue',
        buttonLayout: 'or',
      },
      onComplete(event) {
        console.log('Lead captured:', event.email);
      },
      onLoad(event) {
        console.log('User found:', event.userFound);
      },
      onError(event) {
        console.error('Error:', event.code, event.message);
      },
    });

    document.querySelector('#lead-capture-mount').appendChild(leadCapture.element);
  </script>

  <div id="lead-capture-mount"></div>
  ```

***

## Related

[Overview - Shop SDK](https://shopify.dev/docs/api/shop-sdk/reference/shop-sdk)

***
