Skip to main content
Migrate to Polaris

Version 2025-07 is the last API version to support React-based UI components. Later versions use web components, native UI elements with built-in accessibility, better performance, and consistent styling with Shopify's design system. Check out the upgrade guide to upgrade your extension.

Companies

The company details page displays information about a specific B2B company, including its profile, locations, contacts, and order history. Extensions on these pages help merchants manage B2B relationships and customize company workflows.

  • CRM integration: Sync company data with external CRM systems, update contact information across platforms, or pull in additional customer intelligence to enrich merchant workflows.
  • Credit management: Display real-time credit limits, outstanding balances, payment terms, or risk scores to help merchants make informed decisions about extending credit to B2B customers.
  • Communication workflows: Initiate targeted email campaigns, send payment reminders, schedule follow-ups, or trigger notifications based on company activity and status changes.
  • Compliance and verification: Show KYC (Know Your Customer) status, tax validation results, business license verification, or other compliance checks required for B2B transactions.
  • Custom analytics: Display specialized metrics such as order frequency, average order value by location, product preferences, or seasonal purchasing patterns to inform sales strategies.
Shopify admin company pages showing all available extension target locations.

Use action and block targets to extend company pages with workflows and contextual information that help merchants manage their B2B relationships and company-specific operations.

Action targets open as modal overlays from the More actions menu, while block targets display as inline cards. The examples demonstrate fetching data from Shopify's direct API or your app's backend.

admin.company-details.action.render

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

Extensions at this target can access information about the company 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
import React from 'react';
import {useState} from 'react';
import {
reactExtension,
useApi,
AdminAction,
Banner,
Section,
BlockStack,
Checkbox,
Button,
} from '@shopify/ui-extensions-react/admin';

const TARGET = 'admin.company-details.action.render';

export default reactExtension(TARGET, () => <App />);

function App() {
const {data, close} = useApi(TARGET);
const [loading, setLoading] = useState(false);
const [includeLocations, setIncludeLocations] = useState(true);
const [includeContacts, setIncludeContacts] = useState(true);
const [includeOrders, setIncludeOrders] = useState(false);
const [success, setSuccess] = useState(false);
const [error, setError] = useState(false);

const handleExport = async () => {
setLoading(true);
setSuccess(false);
setError(false);
const companyId = data.selected[0].id;

try {
// Fetch company details from GraphQL Admin API
const companyResponse = await fetch('shopify:admin/api/graphql.json', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
query: `
query GetCompany($id: ID!) {
company(id: $id) {
id
name
externalId
mainContact {
firstName
lastName
email
}
locations(first: 10) {
edges {
node {
id
name
shippingAddress {
address1
city
province
country
zip
}
}
}
}
}
}
`,
variables: {id: companyId},
}),
});

const {data: companyData} = await companyResponse.json();

// Export to CRM through your app's backend
const response = await fetch('https://your-app.com/api/export-to-crm', {
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
company: companyData.company,
includeLocations,
includeContacts,
includeOrders,
}),
});

if (response.ok) {
setSuccess(true);
close();
} else {
setError(true);
}
} catch (err) {
setError(true);
} finally {
setLoading(false);
}
};

return (
<AdminAction
title="Export to CRM"
primaryAction={
<Button
onPress={handleExport}
disabled={loading || success}
>
{loading ? 'Exporting...' : 'Export to CRM'}
</Button>
}
secondaryAction={
<Button onPress={close}>
Cancel
</Button>
}
>
{success && (
<Banner tone="success" dismissible>
Company exported to CRM successfully!
</Banner>
)}
{error && (
<Banner tone="critical" dismissible>
Failed to export company. Please try again.
</Banner>
)}

<Section heading="Export options">
<BlockStack>
<Checkbox
checked={includeLocations}
onChange={setIncludeLocations}
>
Include locations
</Checkbox>
<Checkbox
checked={includeContacts}
onChange={setIncludeContacts}
>
Include contacts
</Checkbox>
<Checkbox
checked={includeOrders}
onChange={setIncludeOrders}
>
Include order history
</Checkbox>
</BlockStack>
</Section>
</AdminAction>
);
}

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

admin.company-details.action.should-render

Controls the render state of an admin action extension on the company details page. Use this target to conditionally show or hide your action extension based on the company's properties, such as status, order count, 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 is evaluated each time the page loads.

Support
Components (0)
APIs (1)

Supported components

-

Available APIs

Examples
import {extension} from '@shopify/ui-extensions/admin';

export default extension(
'admin.company-details.action.should-render',
async ({data}) => {
const companyId = data.selected[0].id;

try {
// Fetch company details from GraphQL Admin API
const response = await fetch(
'shopify:admin/api/graphql.json',
{
method: 'POST',
headers: {'Content-Type': 'application/json'},
body: JSON.stringify({
query: `
query GetCompany($id: ID!) {
company(id: $id) {
id
name
createdAt
}
}
`,
variables: {id: companyId},
}),
}
);

const {data: responseData} = await response.json();
// Check if company has been active for at least 30 days
const createdDate = new Date(responseData.company.createdAt);
const daysSinceCreation = (Date.now() - createdDate.getTime()) / (1000 * 60 * 60 * 24);
// Only show action for established companies
return {display: daysSinceCreation >= 30};
} catch (err) {
console.error('Error fetching company:', err);
return {display: false};
}
}
);

admin.company-details.block.render

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

Extensions at this target can access information about the company 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
import React from 'react';
import {useState, useEffect} from 'react';
import {
reactExtension,
useApi,
AdminBlock,
BlockStack,
Box,
Heading,
InlineStack,
Text,
Badge,
Divider,
Banner,
ProgressIndicator,
} from '@shopify/ui-extensions-react/admin';

const TARGET = 'admin.company-details.block.render';

export default reactExtension(TARGET, () => <App />);

function App() {
const {data} = useApi(TARGET);
const [metrics, setMetrics] = useState(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
const fetchMetrics = async () => {
const companyId = data.selected[0].id;

try {
// Fetch financial metrics from your app's backend
const response = await fetch(
`https://your-app.com/api/company-financials?id=${companyId}`
);
const metricsData = await response.json();
setMetrics(metricsData);
} catch (err) {
console.error('Error fetching metrics:', err);
} finally {
setLoading(false);
}
};

fetchMetrics();
}, [data]);

if (loading) {
return (
<AdminBlock title="Credit & Payment Status">
<BlockStack>
<ProgressIndicator size="small-100" />
<Text>Loading metrics...</Text>
</BlockStack>
</AdminBlock>
);
}

if (!metrics) {
return (
<AdminBlock title="Credit & Payment Status">
<Text>Unable to load financial metrics</Text>
</AdminBlock>
);
}

const utilizationPercent = (metrics.outstandingBalance / metrics.creditLimit) * 100;
const utilizationTone = utilizationPercent > 90 ? 'critical' :
utilizationPercent > 75 ? 'warning' : 'success';

return (
<AdminBlock title="Credit & Payment Status">
<BlockStack>
<Box>
<BlockStack>
<Heading>Credit Limit</Heading>
<Text fontWeight="bold">
${metrics.creditLimit.toLocaleString()}
</Text>
</BlockStack>
</Box>

<Divider />

<Box>
<BlockStack>
<Heading>Outstanding Balance</Heading>
<InlineStack>
<Text fontWeight="bold">
${metrics.outstandingBalance.toLocaleString()}
</Text>
<Badge tone={utilizationTone}>
{utilizationPercent.toFixed(0)}% utilized
</Badge>
</InlineStack>
</BlockStack>
</Box>

<Divider />

<Box>
<BlockStack>
<Heading>Payment History</Heading>
<Text>
Average payment time: {metrics.avgPaymentDays} days
</Text>
<Text>
On-time payments: {metrics.onTimePaymentRate}%
</Text>
</BlockStack>
</Box>

<Divider />

<Box>
<BlockStack>
<Heading>Terms</Heading>
<Text>Net {metrics.paymentTerms} days</Text>
</BlockStack>
</Box>

{metrics.pastDueAmount > 0 && (
<>
<Divider />
<Banner tone="warning">
Past due: ${metrics.pastDueAmount.toLocaleString()}
</Banner>
</>
)}
</BlockStack>
</AdminBlock>
);
}

admin.company-location-details.block.render

Renders an admin block extension inline on the company location details page. Use this target to display location-specific information, such as shipping preferences, inventory availability, or delivery schedules for a particular company location.

Extensions at this target can access information about the company location through the data property in the Block Extension API. Blocks appear as cards on the location page and can show data relevant to that specific location rather than the entire company. This is particularly useful for companies with multiple locations that require different handling or have unique attributes.

Examples
import React from 'react';
import {useState, useEffect} from 'react';
import {
reactExtension,
useApi,
AdminBlock,
BlockStack,
Box,
Heading,
Text,
Banner,
Button,
Divider,
ProgressIndicator,
} from '@shopify/ui-extensions-react/admin';

const TARGET = 'admin.company-location-details.block.render';

export default reactExtension(TARGET, () => <App />);

function App() {
const {data, query, navigation} = useApi(TARGET);
const [locationData, setLocationData] = useState(null);
const [loading, setLoading] = useState(true);

useEffect(() => {
const fetchLocationData = async () => {
const locationId = data.selected[0].id;

try {
// Fetch location details from GraphQL Admin API
const {data: responseData} = await query(
`
query GetCompanyLocation($id: ID!) {
companyLocation(id: $id) {
id
name
shippingAddress {
address1
city
province
zip
}
company {
id
name
}
}
}
`,
{variables: {id: locationId}}
);

// Fetch custom delivery preferences from your app's backend
const preferencesResponse = await fetch(
`https://your-app.com/api/location-preferences?id=${locationId}`
);
const preferences = await preferencesResponse.json();

setLocationData({
location: responseData.companyLocation,
preferences,
});
} catch (err) {
console.error('Error fetching location data:', err);
} finally {
setLoading(false);
}
};

fetchLocationData();
}, [data, query]);

if (loading) {
return (
<AdminBlock title="Delivery Preferences">
<BlockStack>
<ProgressIndicator size="small-100" />
<Text>Loading preferences...</Text>
</BlockStack>
</AdminBlock>
);
}

if (!locationData) {
return (
<AdminBlock title="Delivery Preferences">
<Text>Unable to load delivery preferences</Text>
</AdminBlock>
);
}

const {location, preferences} = locationData;

return (
<AdminBlock title="Delivery Preferences">
<BlockStack>
<Box>
<BlockStack>
<Heading>Preferred Delivery Days</Heading>
<Text>{preferences.deliveryDays.join(', ')}</Text>
</BlockStack>
</Box>

<Divider />

<Box>
<BlockStack>
<Heading>Delivery Window</Heading>
<Text>
{preferences.deliveryWindowStart} - {preferences.deliveryWindowEnd}
</Text>
</BlockStack>
</Box>

<Divider />

<Box>
<BlockStack>
<Heading>Special Instructions</Heading>
<Text>
{preferences.specialInstructions || 'No special instructions'}
</Text>
</BlockStack>
</Box>

<Divider />

<Box>
<BlockStack>
<Heading>Receiving Contact</Heading>
<Text>{preferences.receivingContact.name}</Text>
<Text>{preferences.receivingContact.phone}</Text>
</BlockStack>
</Box>

{preferences.requiresAppointment && (
<>
<Divider />
<Banner tone="info">
Appointment required for delivery
</Banner>
</>
)}

<Button
onPress={() => navigation.navigate('extension://edit-preferences-action')}
>
Edit Preferences
</Button>
</BlockStack>
</AdminBlock>
);
}

  • Focus on B2B workflows: Companies are used for B2B commerce, so design your extensions to support wholesale operations, multi-location management, and credit-based purchasing that align with merchant needs.
  • Handle multi-location scenarios: Companies often have multiple locations with different needs. Design your extensions to work effectively when dealing with company hierarchies and location-specific data.
  • Display financial context clearly: When showing credit limits or outstanding balances, include context like credit utilization percentage, payment history metrics (on-time payment rate, average days to payment), and aging of receivables. Raw numbers without context don't help merchants make credit decisions.

  • Single target per module: Each [[extensions.targeting]] entry in your TOML configuration maps one target to one module file.
  • Location context access: Extensions on the admin.company-location-details.block.render target receive a location ID, not the parent company ID. To access company information, query the location ID and access the company field on the CompanyLocation object.
  • B2B requirement: The GraphQL Company object requires the store to be on a plan that supports B2B capabilities.
  • 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?