> Deprecated:
> Product subscription app extensions won't be supported as of December 3, 2025. You should migrate existing product subscription app extensions to [purchase options extensions](/docs/apps/build/purchase-options/purchase-options-extensions).
You've generated a product subscription app extension, and you now have a project folder with the extension script (either `./index.ts(x)` or `./index.js`). This guide describes the extension points in the script and how the script renders data and UI components.
## Extension points
Each extension point is triggered by a different merchant action, receives different data, and is responsible for handling a distinct part of the subscription experience.
The product subscription app extension uses the following extension points:
> Note
> The extension points must be rendered separately.
Extension points
Extension point |
Mode |
Description |
Admin::Product::SubscriptionPlan::Add |
Add |
Add an existing purchase option to a product or variant. |
Admin::Product::SubscriptionPlan::Create |
Create |
Create a new purchase option |
Admin::Product::SubscriptionPlan::Edit |
Edit |
Edit an existing purchase option |
Admin::Product::SubscriptionPlan::Remove |
Remove |
Remove an existing purchase option from a product or variant |
### Example
The following example shows how to render the extension points in JavaScript and React:
```typescript?title: 'JavaScript'
import {extend} from '@shopify/admin-ui-extensions';
function Add(root, api) {
root.appendChild(root.createText('Hello, world'));
root.mount();
}
function Create() {
/* ... */
}
function Edit() {
/* ... */
}
function Remove() {
/* ... */
}
extend(
'Admin::Product::SubscriptionPlan::Add',
Add,
);
extend(
'Admin::Product::SubscriptionPlan::Create',
Create,
);
extend(
'Admin::Product::SubscriptionPlan::Edit',
Edit,
);
extend(
'Admin::Product::SubscriptionPlan::Remove',
Remove,
);
```
```typescript?title: 'React'
import {extend, render, Text} from '@shopify/admin-ui-extensions-react';
function Add() {
return Hello, world;
}
function Create() {
/* ... */
}
function Edit() {
/* ... */
}
function Remove() {
/* ... */
}
extend(
'Admin::Product::SubscriptionPlan::Add',
render(() => ),
);
extend(
'Admin::Product::SubscriptionPlan::Create',
render(() => ),
);
extend(
'Admin::Product::SubscriptionPlan::Edit',
render(() => ),
);
extend(
'Admin::Product::SubscriptionPlan::Remove',
render(() => ),
);
```
### Expected responses
The response of an extension point will depend on the context in which it was triggered. Here are the expected responses:
#### Product details page
Extension point expected responses in the Shopify admin product details page
Extension point |
Expected reponse |
Admin::Product::SubscriptionPlan::Add |
productId : The id of the current product
variantId : null
|
Admin::Product::SubscriptionPlan::Create |
productId : The id of the current product
variantId : null
|
Admin::Product::SubscriptionPlan::Edit |
sellingPlanGroupId : The id of the selling plan group being edited
productId : The id of the current product
variantId : null
|
Admin::Product::SubscriptionPlan::Remove |
sellingPlanGroupId : The id of the selling plan group being edited
productId : The id of the current product
variantId : null
variantIds : An array of the current product's child variant ids for which you should also remove the selling plan group association
|
#### Variant details page
Extension point expected responses in the Shopify admin variant details page
Extension point |
Expected reponse |
Admin::Product::SubscriptionPlan::Add |
productId : The id of the current variant's parent product
variantId : The id of the current variant
|
Admin::Product::SubscriptionPlan::Create |
productId : The id of the current variant's parent product
variantId : The id of the current variant
|
Admin::Product::SubscriptionPlan::Edit |
sellingPlanGroupId : The id of the selling plan group being edited
productId : The id of the current variant's parent product
variantId : The id of the current variant
|
Admin::Product::SubscriptionPlan::Remove |
sellingPlanGroupId : The id of the selling plan group being edited
productId : The id of the current variant's parent product
variantId : The id of the current variant
variantIds : An empty array because the variant has no child variants
|
## Data rendering
Your extension receives data from the host page. The `Create` callback function includes the data passed into the host page.
### Example
In the following example, the current product is being rendered inside the extension as **(Product 1)**:

In the first line of the `Create` callback function, the `data` variable is assigned to the input data that's passed into the extension from the host page.
- In vanilla JavaScript, input data is passed into the `Create` callback function. Refer to the [JavaScript product subscription app extension template](https://github.com/Shopify/admin-ui-extensions-template/blob/main/scripts/generate/templates/PRODUCT_SUBSCRIPTION/vanilla.template.js).
- In React, input data is passed using the `useData` hook. Refer to the [React product subscription app extension template](https://github.com/Shopify/admin-ui-extensions-template/blob/main/scripts/generate/templates/PRODUCT_SUBSCRIPTION/react.template.js).
```typescript?title: 'JavaScript'
import {extend, Card} from '@shopify/admin-ui-extensions';
function Create(root, api) {
const data = api.data;
// ...
const planTitleCard = root.createComponent(Card, {
sectioned: true,
title: `Create subscription plan for Product id ${data.productId}`,
});
root.appendChild(planTitleCard);
root.mount();
}
extend('Admin::Product::SubscriptionPlan::Create', Create);
```
```typescript?title: 'React'
import {extend, render, useData, Card} from '@shopify/admin-ui-extensions-react';
function Create() {
const data = useData();
// ...
return (
// ...
...
)
}
extend('Admin::Product::SubscriptionPlan::Create', render(() => );
```
## UI components
The `Create` callback function renders the UI components that appear in the canvas of the app overlay.
### Example
The example renders the following UI components:
- [`Card`](/docs/api/product-subscription-extensions/components/card)
- [`Text`](/docs/api/product-subscription-extensions/components/text)
- [`TextField`](/docs/api/product-subscription-extensions/components/textfield)
- [`InlineStack`](/docs/api/product-subscription-extensions/components/inlinestack)

```typescript?title: 'JavaScript'
import {extend, Card, Text, TextField, InlineStack} from '@shopify/admin-ui-extensions';
function Create(api, root) {
// ...
const planDetailsCard = root.createComponent(Card, {
sectioned: true,
title: 'Delivery and discount',
});
root.appendChild(planDetailsCard);
const inlineStack = root.createComponent(InlineStack);
planDetailsCard.appendChild(inlineStack);
const deliveryFrequencyField = root.createComponent(TextField, {
type: 'number',
label: 'Delivery frequency (in weeks)',
value: undefined,
onChange(value) {
deliveryFrequencyField.updateProps({
value,
});
},
});
inlineStack.appendChild(deliveryFrequencyField);
const percentageOffField = root.createComponent(TextField, {
type: 'number',
label: 'Percentage off (%)',
value: undefined,
onChange(value) {
percentageOffField.updateProps({
value,
});
},
});
inlineStack.appendChild(percentageOffField);
const actionsElement = root.createComponent(InlineStack, {distribution: 'fill'});
root.appendChild(actionsElement);
actionsElement.appendChild(secondaryButton);
const primaryButtonStack = root.createComponent(InlineStack, {
distribution: 'trailing',
});
actionsElement.appendChild(primaryButtonStack);
primaryButtonStack.appendChild(primaryButton);
root.mount();
}
extend('Admin::Product::SubscriptionPlan::Create', Create);
```
```typescript?title: 'React'
import {extend, render, Card, Text, TextField, InlineStack} from '@shopify/admin-ui-extensions-react';
function Create() {
// ...
return (
<>
Create plan
{actions}
>
);
}
extend('Admin::Product::SubscriptionPlan::Create', render(() => );
```
For more information, refer to the following resources:
- [UI components for the product subscription app extension](/docs/api/product-subscription-extensions/components)
- [JavaScript product subscription app extension template](https://github.com/Shopify/admin-ui-extensions-template/blob/main/scripts/generate/templates/PRODUCT_SUBSCRIPTION/vanilla.template.js)
- [React product subscription app extension template](https://github.com/Shopify/admin-ui-extensions-template/blob/main/scripts/generate/templates/PRODUCT_SUBSCRIPTION/react.template.js)
## Next steps
- [Authenticate requests between your extension and app server](/docs/apps/build/purchase-options/product-subscription-app-extensions/authenticate-extension-requests)