Skip to main content

Gift cards

Gift card details pages display balance, status, expiration dates, and transaction history for individual gift cards. Extensions on these pages help merchants manage gift card workflows, track usage patterns, and integrate with external loyalty or CRM systems.

  • Balance adjustments: Add or deduct gift card balances with custom approval workflows and audit logging.
  • Fraud detection: Display risk indicators and suspicious activity alerts based on gift card usage patterns and transaction history.
  • Loyalty integration: Connect gift cards to external loyalty programs, enabling point conversions and reward redemptions.
  • Expiration management: Help merchants extend expiration dates or send reminder notifications to customers before gift cards expire.
  • Transaction history export: Export detailed gift card transaction records for accounting and compliance purposes.
Shopify admin gift card pages showing all available extension target locations.

Use action and block targets to extend the gift cards details page with workflows and contextual information. Action targets open as modal overlays from the More actions menu, while block targets display as inline cards.

Extensions can query and mutate Shopify data using the direct API, or call your app's backend for custom business logic and external integrations.

admin.gift-card-details.action.render

Renders an admin action extension on the gift card details page. Merchants can access this extension from the More actions menu. Use this target to provide workflows that operate on gift card data, such as syncing with external systems, exporting gift card information, or managing credit terms.

Extensions at this target can access gift card data through the data property in the Action Extension API. The action renders in a modal overlay, providing space for multi-step workflows, forms, and confirmations.

Examples

jsx

import {render} from 'preact';
import {useState} from 'preact/hooks';

export default async () => {
render(<Extension />, document.body);
};

const Extension = () => {
const [loading, setLoading] = useState(false);
const [success, setSuccess] = useState(false);
const [error, setError] = useState(null);
const [includeTransactions, setIncludeTransactions] = useState(true);
const [includeCustomer, setIncludeCustomer] = useState(true);

const handleExport = async () => {
setLoading(true);
setError(null);
const giftCardId = shopify.data.selected[0].id;

try {
const response = await fetch('https://your-app.com/api/gift-cards/export', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
giftCardId,
includeTransactions,
includeCustomer,
}),
});

if (response.ok) {
const {downloadUrl} = await response.json();
setSuccess(true);
window.open(downloadUrl, '_blank');
shopify.close();
} else {
const {message} = await response.json();
setError(message || 'Export failed');
}
} catch (err) {
setError('Failed to connect to export service');
} finally {
setLoading(false);
}
};

return (
<s-admin-action heading="Export Gift Card to CSV">
<s-stack direction="block" gap="base">
{success && (
<s-banner tone="success" dismissible={false}>
CSV exported! Download starting...
</s-banner>
)}
{error && (
<s-banner tone="critical" dismissible={false}>
{error}
</s-banner>
)}

<s-section heading="Export Options">
<s-stack direction="block" gap="small">
<s-checkbox
label="Include transaction history"
checked={includeTransactions}
onChange={(e) => setIncludeTransactions(e.currentTarget.checked)}
/>
<s-checkbox
label="Include customer details"
checked={includeCustomer}
onChange={(e) => setIncludeCustomer(e.currentTarget.checked)}
/>
</s-stack>
</s-section>

<s-text color="subdued">
Export includes gift card balance, status, and selected details.
</s-text>

<s-button-group>
<s-button
variant="primary"
onClick={handleExport}
disabled={loading || success}
>
{loading ? 'Exporting...' : 'Export CSV'}
</s-button>
<s-button onClick={() => shopify.close()}>Cancel</s-button>
</s-button-group>
</s-stack>
</s-admin-action>
);
};

Anchor to Gift card details action (should render) ,[object Object]Gift card details action (should render) target

admin.gift-card-details.action.should-render

Controls the render state of an admin action extension on the gift card details page. Use this target to conditionally show or hide your action extension based on the gift card's properties, such as status, configuration, or specific business requirements.

This target returns a boolean value that determines whether the corresponding action extension appears in the More actions menu. The extension evaluates each time the page loads.

Support
Components (0)
APIs (1)

Supported components

-

Available APIs

Examples

jsx

export default async () => {
const giftCardId = shopify.data.selected[0].id;

try {
// Check if your external system has analytics data for this gift card
const response = await fetch('https://your-app.com/api/gift-card-analytics/check', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
giftCardId,
checkType: 'has_analytics_data',
}),
});

if (!response.ok) {
console.error('Analytics check failed:', response.status);
return { display: false };
}

const result = await response.json();

// Show action only if external analytics data exists for this gift card
return { display: result.hasAnalyticsData && result.dataPointsCount > 0 };
} catch (err) {
console.error('Error checking gift card analytics:', err);
return { display: false };
}
};

admin.gift-card-details.block.render

Renders an admin block extension inline on the gift card details page. Use this target to display contextual information, analytics, or status updates related to the gift card without requiring merchant interaction to open a modal.

Extensions at this target can access gift card data through the data property in the Block Extension API. Blocks appear as cards on the page and can show real-time data, insights, or quick actions, providing persistent visibility for information merchants need to see at a glance.

Examples

jsx


import {render} from 'preact';
import {useState, useEffect} from 'preact/hooks';

export default async () => {
render(<Extension />, document.body);
};

const Extension = () => {
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
const [externalData, setExternalData] = useState(null);

useEffect(() => {
fetchExternalData();
}, []);

const fetchExternalData = async () => {
setLoading(true);
setError(false);
const giftCardId = shopify.data.selected[0].id;

try {
const response = await fetch('https://your-app.com/api/gift-card/external-data', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({giftCardId}),
});

if (response.ok) {
const data = await response.json();
setExternalData(data);
} else {
setError(true);
}
} catch (err) {
setError(true);
} finally {
setLoading(false);
}
};

if (loading) {
return (
<s-admin-block heading="Loyalty System Data">
<s-stack direction="block" gap="base">
<s-spinner />
<s-text color="subdued">Loading external data...</s-text>
</s-stack>
</s-admin-block>
);
}

if (error) {
return (
<s-admin-block heading="Loyalty System Data">
<s-banner tone="critical" dismissible={false}>
Failed to load external data.
</s-banner>
<s-button onClick={fetchExternalData}>Retry</s-button>
</s-admin-block>
);
}

return (
<s-admin-block heading="Loyalty System Data">
<s-stack direction="block" gap="base">
<s-section heading="External Balance">
<s-stack direction="inline" gap="base">
<s-text>Loyalty Points Earned:</s-text>
<s-badge tone="success">{externalData?.loyaltyPoints || 0} pts</s-badge>
</s-stack>
</s-section>

<s-divider />

<s-section heading="Usage History">
<s-stack direction="block" gap="small">
<s-text color="subdued">Last used: {externalData?.lastUsed || 'Never'}</s-text>
<s-text color="subdued">Total transactions: {externalData?.transactionCount || 0}</s-text>
<s-text color="subdued">Linked customer: {externalData?.customerEmail || 'None'}</s-text>
</s-stack>
</s-section>

<s-link href={`https://your-app.com/dashboard/gift-cards/${shopify.data.selected[0].id}`}>
View full history in dashboard →
</s-link>
</s-stack>
</s-admin-block>
);
};

  • Display balance context: Always show both current balance and initial value when displaying gift card information. This helps merchants understand usage patterns and whether a gift card is partially used, fully depleted, or unused.
  • Check enabled status before operations: Gift cards can be disabled by merchants or automatically by the system. Before displaying actions like "send to customer" or "sync to external system," verify the gift card's enabled status to avoid operations on disabled cards.
  • Handle balance adjustments with care: When building extensions that modify gift card balances using giftCardCredit or giftCardDebit, require explicit merchant confirmation and display the resulting balance before applying changes. Gift card balance errors can create customer service issues.
  • Reconcile external integrations: If your extension syncs gift cards with external loyalty platforms, ensure transaction histories stay synchronized. A mismatch between Shopify's balance and the external system's balance creates confusion and potential fraud issues.
  • Respect expiration dates: When displaying or exporting gift card data, prominently show expiration dates if set. Merchants need this information to proactively reach out to customers before cards expire and to ensure compliance with gift card regulations in their jurisdiction.

  • Single target per module: Each [[extensions.targeting]] entry in your TOML configuration maps one target to one module file.
  • Gift card code immutability: Gift card codes cannot be modified after creation. The API only exposes lastCharacters (final 4 digits) and maskedCode. The giftCardUpdate mutation has no code field.
  • Permanent deactivation: After you've used the giftCardDeactivate mutation, gift cards can't be re-enabled.
  • Transaction history pagination: Gift card transaction history returns a maximum of 250 transactions per request.
  • Block target visibility: Block extensions must be manually added and pinned by merchants before they appear.
  • Block collapse behavior: Returning null from a block extension collapses the block rather than removing it from the page. Blocks can't be fully hidden at runtime.

Was this page helpful?