--- gid: f22ec76a-b20f-4f2b-a3a4-c556cf603ddf title: Build an admin print action description: Learn how to create admin print action extensions on resource and index pages in the Shopify admin. --- This guide demonstrates how to build a basic admin print action extension that lets users print invoices and packing slips directly from order detail pages in the Shopify admin. ![The open print action modal. The admin print action has a choice list to select documents.](/assets/admin/admin-actions-and-block/build-an-admin-print-action/print-action-extension-example.png) ## What you'll learn In this tutorial, you'll learn how to do the following tasks: - Serve a printable document from your app's backend. - Create an admin print action extension that displays on the order details page. - Create a UI for the extension that lets merchants select the documents to print. - Run your extension locally and test it on a development store. Scaffold an app with the `read_orders` access scope that uses [Shopify CLI 3.71 or higher](/docs/api/shopify-cli#upgrade). - You need to explicitly grant the `read_orders` [access scope](/docs/api/usage/access-scopes) to your custom app. - You need to [request](https://shopify.dev/docs/api/usage/access-scopes#orders-permissions) the `read_all_orders` access scope. You will need this for your extension to work with orders that are more than 60 days old. - You need to request access to [protected customer data](/docs/apps/launch/protected-customer-data). - You need to create at least one order in your development store to test the extension. Make sure to mark the order as paid to convert it from a draft order to a fulfilled order. ## Create a route to serve the printable document To begin, you need to create a route in your app that returns the printable documents for an order. You can use JavaScript to customize the document on your app's backend, but the route must return static HTML without any scripts. Add a new route file at `app/routes/print.js`. This file contains the route that will serve the printable document. [Remix routes](https://remix.run/docs/en/main/guides/mdx#routes) Use `authenticate.admin(request)` to authenticate your request and retrieve the `cors` utility. Define and handle any routes or URL parameters so you can configure the order and documents to be printed. After you've authenticated your app, you can query the GraphQL Admin API to fetch data which you can use to populate the document. Using the data you've fetched, return the printable document as an HTML response. Be sure to wrap your response in the `cors` method to automatically set CORS headers. If you need to set CORS headers manually, then set `Access-Control-Allow-Origin: "*"` after authenticating the request. Set the title for the printable document using the [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/title) element. Most browsers will include the document's title by default on the final printed page. </Substep> <Substep> <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/app/routes/print.js" tag="build-admin-print-action.print-src-two" /> If your extension will return multiple documents, be sure to create visual breaks in the CSS so each document is printed as a separate page and users know where each document begins. We recommend using the CSS `@media print` rule and styles here to ensure that the document prints correctly. </Substep> <Substep> <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/app/routes/print.js" tag="build-admin-print-action.email-obfuscation"/> Shopify CLI uses Cloudflare tunnels to serve your app. These tunnels default to obfuscating email addresses in the app. Wrap the email in a magic comment to ensure that the email address is visible in the document. <Resources> [Cloudflare email obfuscation](https://developers.cloudflare.com/waf/tools/scrape-shield/email-address-obfuscation/#prevent-cloudflare-from-obfuscating-email) </Resources> </Substep> </Step> <Step> ## Create a new extension After you've created a route to serve the printable document, you can create a new admin print action extension that will display on the order details page. The extension will use the route you created in the previous step to fetch the documents. Use Shopify CLI to [generate starter code](/docs/api/shopify-cli/app/app-generate-extension) for your action extension. <Substep> 1. Navigate to your app directory: <Codeblock terminal> ```bash cd <directory> ``` </Codeblock> 2. Run the following command to create a new admin action extension: <Codeblock terminal> ```bash shopify app generate extension --template admin_print --flavor react ``` </Codeblock> The command creates a new extension template in your app's `extensions` directory with the following structure: <Codeblock title="Admin print action structure"> ```text extensions/admin-print ├── README.md ├── locales │ ├── en.default.json // The default locale for the extension │ └── fr.json // The French language translations for the extension ├── package.json ├── shopify.extension.toml // The config file for the extension └── src └── PrintActionExtension.jsx // The code that defines the print action's UI and behavior ``` </Codeblock> </Substep> </Step> <Step> ## Write the extension's UI You can configure the extension UI to allow merchants to select the documents they want to print. Complete the following steps to write the extension's UI: <Substep> <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/admin-print/shopify.extension.toml" tag="print-action-extension.configuration"/> ### Review the configuration The extension's `.toml` file stores the extension's static configuration. To ensure that the print action displays on the order details page, validate that the `target` is set to `admin.order-details.print-action.render`. <Resources> [admin.order-details.print-action.render](/docs/api/admin-extensions/unstable/extension-targets#print-locations) </Resources> </Substep> <Substep> <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/admin-print/src/PrintActionExtension.jsx" tag="build-admin-print-action.create-ui-one"/> ### Use UI components Admin UI extensions are rendered using [Remote UI](https://github.com/Shopify/remote-dom/tree/remote-ui), which is a fast and secure remote-rendering framework. Because Shopify renders the UI remotely, components used in the extensions must comply with a contract in the Shopify host. We provide these components through the admin UI extensions library. <Resources> [Admin UI extensions components](/docs/api/admin-extensions/components) </Resources> </Substep> <Substep> <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/admin-print/src/PrintActionExtension.jsx" tag="build-admin-print-action.create-ui-two"/> ### Note the target You can view the source of your extension in the `src/PrintActionExtension.jsx` file. This file defines a functional React component exported to run at the extension's target. If you ever want to expose the extension at a different target, you need to update the value here and in the `.toml` file. <Troubleshooting type="warning" title="Caution"> #### The extension is not rendering The extension point in the component export must match the extension point defined in your `.toml` file, or the extension won't render. </Troubleshooting> </Substep> <Substep> <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/admin-print/src/PrintActionExtension.jsx" tag="build-admin-print-action.set-src"/> Configure your app's state to set the printable source URL based on the user's inputs. Passing the ID of the current resource to the `AdminPrintAction` component sets the document to be previewed and printed. </Substep> <Substep> <CodeRef extension="react" href="https://github.com/Shopify/example-admin--action-and-block--react/blob/main/extensions/admin-print/src/PrintActionExtension.jsx" tag="build-admin-print-action.create-ui-three"/> ### Render a UI To build your admin print action's interface, return components from `src/PrintActionExtension.jsx`. Setting the `src` prop of the `AdminPrintAction` container component will display the print preview of the document and enable printing. HTML, PDF and images are supported. <Notice type="note" title="Tip"> If there is no document to print, then pass `null` to the `src` prop. You might also want to add an error banner to your extension's UI to indicate to the user why no document is available. </Notice> </Substep> </Step> <Step> ## Test the extension You can use the developer console to run your app's server and preview your extension. After you preview the extension, changes to your extension's code automatically reload the extension. You can preview your extension and see it update live as you make changes to the code. <Substep> After you've built the extension, test it with the following steps: 1. Navigate to your app directory: <Codeblock terminal> ```bash cd <directory> ``` </Codeblock> 2. To build and preview your app, either start or restart your server with the following command: <Codeblock terminal> ```bash shopify app dev ``` </Codeblock> 3. Press `p` to open the developer console. 4. In the developer console page, click on the preview link for the print action extension. 5. The order details page opens. If you don't have an order in your store, then you need to create one. <Notice type="warning" title="Warning"> If you do not have the `read_all_orders` access scope, ensure that the order you use to test the extension is less than 60 days old. Otherwise, your app will fail when fetching the order data. </Notice> 6. To launch your extension, click the **Print** dropdown list and select your extension. 7. Select some options and click **Continue to print**. 8. The browser print dialog opens, and you can print the document. </Substep> </Step> </StepSection> <NextSteps> ### Next steps <CardGrid> <LinkCard href="/docs/apps/admin/admin-actions-and-blocks/build-an-admin-action"> #### Action extension Complete a tutorial series on building an issue tracker action extension. </LinkCard> <LinkCard href="/docs/api/admin-extensions/extension-targets"> #### Extension targets Learn about the surfaces in the Shopify admin where you can create admin extensions. </LinkCard> <LinkCard href="/docs/api/admin-extensions/components"> #### Components Learn about the full set of available components for writing admin UI extensions. </LinkCard> </CardGrid> </NextSteps>