Send print jobs to configured printers for labels, documents, and other printable content. Supports ZPL label printing and PDF-to-ZPL conversion for thermal printers.
ctx.ui.interactive.print(config);Config
PrintJob | PrintJob[]One or more print jobs to execute. Each job specifies the content type, data, and target printer.
stringThe title displayed on the print card. Defaults to "Print".
stringHelp text displayed below the title.
booleanWhen true, jobs print automatically when the step loads. Default is false.
booleanWhen true, the flow continues automatically after printing completes. Default is false.
booleanWhen false, hides the print button after the first print. Useful for preventing duplicate labels. Default is true.
Print job properties
Each print job in the jobs array has the following properties:
"zpl" | "rawPdf"The content type:
"zpl"- ZPL commands sent directly to a thermal printer"rawPdf"- PDF document converted to ZPL for thermal printing
stringA friendly name for the print job, shown in the print queue.
stringThe printer to use, as defined in your keelconfig.yaml. If omitted, uses the user's default printer.
string | string[]The ZPL content to print. Required for zpl type when url is not provided.
stringA URL to fetch the print content from. Required for rawPdf type, optional for zpl type.
PDF-specific properties
When using type: "rawPdf", you can configure the PDF-to-ZPL conversion:
numberThe DPI (dots per inch) of the output. Default is 300.
numberThe width of the label in dots. For example, a 4" label at 300 DPI is 1200 dots. Default is 1200.
numberThe height of the label in dots. For example, a 6" label at 300 DPI is 1800 dots. Default is 1800.
Prerequisites
The print component requires QZ Tray (opens in a new tab) to be installed on the user's workstation. QZ Tray is a desktop application that bridges web applications to local printers.
Setting up QZ Tray
- Download and install QZ Tray from qz.io (opens in a new tab)
- Launch QZ Tray (it runs in the system tray)
- Configure printer mappings in the Keel console under Settings > Devices
Printer mappings
Printers defined in your schema map to physical printers on each workstation. This allows the same flow to work across different warehouse locations where printer names differ.
For example, if your schema defines a printer called "shipping-label", each workstation maps this to their local printer (e.g., "Zebra ZP450" in the shipping office, "Zebra GC420" in the warehouse).
Usage
Printing a ZPL label
Send ZPL commands directly to a thermal printer:
await ctx.ui.page({
title: "Print shipping label",
content: [
ctx.ui.interactive.print({
title: "Shipping label",
description: "Print the shipping label for this order",
jobs: {
type: "zpl",
data: `^XA
^FO50,50^ADN,36,20^FDOrder: ${order.reference}^FS
^FO50,100^ADN,36,20^FD${order.customerName}^FS
^FO50,150^ADN,36,20^FD${order.address}^FS
^FO50,250^BY3^BCN,100,Y,N,N^FD${order.trackingNumber}^FS
^XZ`,
printer: "shipping-label",
},
}),
],
});Printing multiple labels
Print multiple labels in a single step:
await ctx.ui.page({
title: "Print pallet labels",
content: [
ctx.ui.interactive.print({
title: "Pallet labels",
description: `Printing ${pallets.length} pallet labels`,
jobs: pallets.map((pallet) => ({
type: "zpl",
name: `Pallet ${pallet.reference}`,
data: generatePalletLabel(pallet),
printer: "warehouse-label",
})),
}),
],
});Printing from a URL
Fetch ZPL content from an external source:
await ctx.ui.page({
title: "Print label",
content: [
ctx.ui.interactive.print({
jobs: {
type: "zpl",
url: `https://labels.example.com/shipping/${order.id}`,
printer: "shipping-label",
},
}),
],
});Printing a PDF as a label
Convert a PDF to ZPL for thermal printing:
await ctx.ui.page({
title: "Print pick list",
content: [
ctx.ui.interactive.print({
title: "Pick list",
jobs: {
type: "rawPdf",
url: pickList.pdfUrl,
printer: "warehouse-label",
dpi: 300,
pageWidth: 1200, // 4 inches at 300 DPI
pageHeight: 1800, // 6 inches at 300 DPI
},
}),
],
});Auto-printing
For streamlined workflows, enable auto-print to send jobs immediately:
await ctx.ui.page({
title: "Shipping",
content: [
ctx.ui.display.keyValue({
data: [
{ key: "Order", value: order.reference },
{ key: "Carrier", value: order.carrier },
],
}),
ctx.ui.interactive.print({
title: "Shipping label",
autoPrint: true,
allowReprint: false,
jobs: {
type: "zpl",
data: shippingLabel,
printer: "shipping-label",
},
}),
],
});Example: Shipping workflow
A complete example printing shipping labels and packing slips:
export default ShipOrder(async (ctx, inputs) => {
const order = await ctx.models.order.findOne({
where: { id: inputs.orderId },
});
// Generate shipping label
const shippingLabel = await generateShippingLabel(order);
// Print labels
await ctx.ui.page({
stage: "print",
title: "Print shipping documents",
content: [
ctx.ui.display.header({ title: `Order ${order.reference}` }),
ctx.ui.display.keyValue({
data: [
{ key: "Customer", value: order.customerName },
{ key: "Items", value: `${order.lineItems.length} items` },
{ key: "Carrier", value: order.carrier },
],
}),
ctx.ui.interactive.print({
title: "Shipping documents",
description: "Print shipping label and packing slip",
autoPrint: true,
jobs: [
{
type: "zpl",
name: "Shipping label",
data: shippingLabel.zpl,
printer: "shipping-label",
},
{
type: "rawPdf",
name: "Packing slip",
url: order.packingSlipUrl,
printer: "document-printer",
dpi: 300,
pageWidth: 2400, // 8" at 300 DPI
pageHeight: 3300, // 11" at 300 DPI
},
],
}),
],
});
// Mark order as shipped
await ctx.models.order.update({
where: { id: order.id },
values: {
status: "shipped",
shippedAt: new Date(),
trackingNumber: shippingLabel.trackingNumber,
},
});
return ctx.ui.complete({
title: "Order shipped",
content: [
ctx.ui.display.keyValue({
data: [
{ key: "Order", value: order.reference },
{ key: "Tracking", value: shippingLabel.trackingNumber },
],
}),
],
});
});Print queue
The print component displays a print queue showing job status. Users can view the queue by clicking the ⋮ menu on the print card. The queue shows:
- Pending - Job waiting to be sent
- Printing - Job currently printing
- Complete - Job finished successfully
- Error - Job failed to print
If a printer mapping is missing, jobs are sent to the user's default printer and a warning is displayed.