Hi.. I have app which has PrintActionExtension and my app is using node template for backend. I have moved the api route above validateAuthenticatedSession and also added origin “https://admin.shopify.com” for cors. But it still showing CORS Error. Can anyone have come up with similar problem ?
This is my index.js for server.
// @ts-check
import { join } from "path";
import { readFileSync } from "fs";
import express from "express";
import serveStatic from "serve-static";
import cors from "cors";
import shopify from "./shopify.js";
import productCreator from "./product-creator.js";
import PrivacyWebhookHandlers from "./privacy.js";
const PORT = parseInt(
process.env.BACKEND_PORT || process.env.PORT || "3000",
10
);
const STATIC_PATH =
process.env.NODE_ENV === "production"
? `${process.cwd()}/frontend/dist`
: `${process.cwd()}/frontend/`;
const app = express();
app.use(express.static("public"));
const uiExtensionCorsOpts = {
origin: "https://admin.shopify.com",
methods: "GET,OPTIONS",
allowedHeaders: "Content-Type,Authorization",
};
app.options("/api/print.html", cors(uiExtensionCorsOpts));
app.get("/api/print.html",cors(uiExtensionCorsOpts) ,async (_req, res) => {
try {
const html = `
<!DOCTYPE html>
<html>
<head>
<title>Order Details</title>
<style>
body { font-family: Arial; padding: 20px; }
.container { max-width: 800px; margin: 0 auto; }
h2 { margin-bottom: 20px; }
p { margin: 10px 0; }
</style>
</head>
<body>
<div class="container">
<h2>Order Details</h2>
<p><strong>Submission ID:</strong> 8123456789</p>
<p><strong>Order ID:</strong> 1234567890</p>
<p><strong>Date:</strong> 2025-05-25</p>
</div>
</body>
</html>
`;
res.type("text/html").send(html);
} catch (error) {
res.status(500).send("Error generating print view");
}
});
app.get(shopify.config.auth.path, shopify.auth.begin());
app.get(
shopify.config.auth.callbackPath,
shopify.auth.callback(),
shopify.redirectToShopifyOrAppRoot()
);
app.post(
shopify.config.webhooks.path,
shopify.processWebhooks({ webhookHandlers: PrivacyWebhookHandlers })
);
app.use("/api/*", shopify.validateAuthenticatedSession());
app.use(express.json());
And also adding PrintActionExtension.jsx
import {
reactExtension,
useApi,
AdminPrintAction,
Banner,
BlockStack,
Checkbox,
Text,
} from "@shopify/ui-extensions-react/admin";
import { useEffect, useState } from "react";
// The target used here must match the target used in the extension's toml file (./shopify.extension.toml)
const TARGET = "admin.order-details.print-action.render";
const baseSrc = `https://cdn.shopify.com/static/extensibility/print-example`;
export default reactExtension(TARGET, () => <App />);
function App() {
// The useApi hook provides access to several useful APIs like i18n and data.
const { i18n, data } = useApi(TARGET);
const [src, setSrc] = useState(null);
// It's best practice to load a printable src when first launching the extension.
const [document1, setDocument1] = useState(true);
const [document2, setDocument2] = useState(false);
// data has information about the resource to be printed.
console.log({ data });
/*
This template fetches static documents from the CDN to demonstrate printing.
However, when building your extension, you should update the src document
to match the resource that the user is printing. You can do this by getting the
resource id from the data API and using it to create a URL with a path to your app
that shows the correct document. For example, you might use a URL parameter to
render an invoice for a specific order.
`/print/invoice&orderId=${data.selected[0].id}`
*/
useEffect(() => {
setSrc("https://trigger-property-mexico-apr.trycloudflare.com/api/print.html");
}, [data]);
return (
/*
The AdminPrintAction component provides an API for setting the src of the Print Action extension wrapper.
The document you set as src will be displayed as a print preview.
When the user clicks the Print button, the browser will print that document.
HTML, PDFs and images are supported.
The `src` prop can be a...
- Full URL: https://cdn.shopify.com/static/extensibility/print-example/document1.html
- Relative path in your app: print-example/document1.html or /print-example/document1.html
- Custom app: protocol: app:print (https://shopify.dev/docs/api/admin-extensions#custom-protocols)
*/
<AdminPrintAction src={src}>
<BlockStack blockGap="base">
<Banner tone="warning" title={i18n.translate("warningTitle")}>
{i18n.translate("warningBody")}
</Banner>
<Text fontWeight="bold">{i18n.translate("documents")}</Text>
<Checkbox
name="document-1"
checked={document1}
onChange={(value) => {
setDocument1(value);
}}
>
{i18n.translate("document1")}
</Checkbox>
<Checkbox
name="document-2"
checked={document2}
onChange={(value) => {
setDocument2(value);
}}
>
{i18n.translate("document2")}
</Checkbox>
</BlockStack>
</AdminPrintAction>
);
}