---
title: Migrate lead capture to the Shop SDK
description: >-
  Move your storefront from the shop-lead-capture component to the new Shop SDK
  lead-capture feature.
source_url:
  html: 'https://shopify.dev/docs/api/shop/guides/use-cases/migrate-lead-capture'
  md: 'https://shopify.dev/docs/api/shop/guides/use-cases/migrate-lead-capture.md'
---

# Migrate lead capture to the Shop SDK

This guide shows you how to move an existing lead capture integration from the `<shop-lead-capture>` component to the [Shop SDK](https://shopify.dev/docs/api/shop/guides/shop-sdk) `lead-capture` feature. The customer-facing flow stays the same. What changes is how you load, configure, and mount it: HTML attributes and global callbacks become a single programmatic API.

***

## Why migrate

* One loader script powers every Shop feature, so you can add sign-in and recognition without shipping more bundles.
* Configuration and event handlers are plain JavaScript, so there are no global `window` callbacks to wire up.

***

## What changes

* **Loader:** the per-feature `loader.lead-capture.esm.js` bundle becomes the single `loader.sdk.esm.js` loader.
* **Setup:** you initialize the SDK once with `window.ShopSDK.initialize()`, then create the feature with `sdk.create('lead-capture', config)` instead of placing a `<shop-lead-capture>` element.
* **Configuration:** kebab-case HTML attributes become camelCase properties in an `attributes` object.
* **Callbacks:** global functions referenced by name become handler functions you pass inline.
* **Rendering:** instead of the element rendering where you placed it, you mount the element the SDK returns.

***

## Requirements

* An existing integration that uses the `<shop-lead-capture>` component.
* A [Shop app](https://shopify.dev/docs/api/shop/guides/creating-a-client) with a client ID.

***

## Step 1: Replace the loader and initialize the SDK

Swap the lead capture loader script for the Shop SDK loader, then call `initialize` with your client ID. The `api-key` you set on the component moves to the `apiKey` option, and the locale you encoded in the script URL moves to the `locale` option. To preload the lead capture code, set `features['lead-capture']` to `true`.

## Before

```html
<script src="https://cdn.shopify.com/shopifycloud/shop-js/modules/v2/loader.lead-capture.esm.js" type="module"></script>
```

## After

```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',
    features: {
      'lead-capture': true, // Preload the lead capture code
    },
  });
</script>
```

***

## Step 2: Replace the component with `sdk.create()`

Remove the `<shop-lead-capture>` element and create the feature with `sdk.create('lead-capture', config)`. The method returns a Promise that resolves once the feature is ready. The SDK builds the underlying element for you, so add a container and append `instance.element` where you want lead capture to appear.

## Before

```html
<shop-lead-capture
  api-key="YOUR_CLIENT_ID"
  email-input-selector="#email"
  on-load="handleLoad"
  on-complete="handleComplete">
</shop-lead-capture>
```

## After

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


// Mount the element where the component used to render
document.querySelector('#lead-capture-container').appendChild(leadCapture.element);
```

***

## Step 3: Map component attributes

Move each attribute from the element into the `attributes` object, using its camelCase name. The `api-key` attribute is the exception: set it once as `apiKey` in `initialize` instead.

| Component attribute | SDK configuration |
| - | - |
| `api-key` | `apiKey` in `initialize()` |
| `dev-mode` | `attributes.devMode` (set to `true`) |
| `email-input-selector` | `attributes.emailInputSelector` |
| `phone-capture` | `attributes.phoneCapture` (set to `true`) |
| `phone-capture-disclosure-text` | `attributes.phoneCaptureDisclosureText` |

***

## Step 4: Replace event callbacks

The component referenced callbacks by name and required you to assign each function to the `window` scope. With the SDK, you pass the functions directly in the config object, so you can delete the `window` assignments.

| Component attribute | SDK handler |
| - | - |
| `on-load` | `onLoad` |
| `on-authenticate` | `onAuthenticate` |
| `on-confirm-success` | `onConfirmSuccess` |
| `on-complete` | `onComplete` |
| `on-restart` | `onRestart` |
| `on-error` | `onError` |

## Before

```javascript
window.handleLoad = (event) => {
  console.log('Loaded, user found:', event.userFound);
};


window.handleComplete = (event) => {
  console.log('Lead captured:', event.email);
};
```

## After

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

If you offer a discount, the `onAuthenticate` handler now returns a Promise that resolves to the discount object, so mark it `async`. Returning a discount from `onAuthenticate` is what drives the discount flow.

## Before

```javascript
window.handleAuthenticate = () => {
  return {
    discount: {code: 'WELCOME10'},
  };
};
```

## After

```javascript
const leadCapture = await sdk.create('lead-capture', {
  attributes: {
    emailInputSelector: '#email',
  },
  async onAuthenticate() {
    return {
      discount: {code: 'WELCOME10'},
    };
  },
});
```

***

## Step 5: Update methods and cleanup

Call methods on the instance that `sdk.create()` returns instead of querying the element in the DOM. The `start` method now takes the email as a string rather than an object.

| Component (before) | SDK instance (after) |
| - | - |
| `element.start({email})` | `leadCapture.start(email)` |
| `element.notifyEmailFieldShown()` | `leadCapture.notifyEmailFieldShown()` |
| Remove the element from the DOM | `leadCapture.destroy()` |

## JavaScript

```javascript
// Start the flow with a pre-filled email
leadCapture.start('user@example.com');


// Tear down the instance and remove its element when you're done
leadCapture.destroy();
```

***

## Next steps

* Follow the [lead capture](https://shopify.dev/docs/api/shop/guides/use-cases/lead-capture) guide for the full SDK setup.
* Review [Set up the Shop SDK](https://shopify.dev/docs/api/shop/guides/shop-sdk) for SDK-wide configuration and event handlers.
* See the [lead capture reference](https://shopify.dev/docs/api/shop-sdk/reference/lead-capture) for the complete list of attributes, handlers, and event types.

***
