Enable Dark Mode!
how-to-build-a-chrome-os-printing-extension.jpg
By: Advaith B G

How to Build a Chrome OS Printing Extension

Technical

Printing documents directly from web pages on Chrome OS has become more powerful than ever, thanks to the Chrome Extensions API. Whether you are developing a kiosk application, automating print workflows, or building enterprise-level print management tools, leveraging Chrome extensions gives you precise control over printers and print jobs.

In this guide, we’ll walk through a working example: a web page that interacts with a Chrome OS extension to list available printers, send print jobs, and manage print tasks. We’ll explore the HTML and JavaScript on the web page, explain how the extension communicates with it, and touch upon the role of the background worker in handling printing tasks.

The Web Page: User Interface for Printing

We can start with a simple web page that allows users to

  • List available printers connected to Chrome OS.
  • Submit a PDF URL to print on a selected printer.

In our index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>PRINT PDF</title>
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
  </head>
  <body class="bg-light d-flex align-items-center justify-content-center vh-100">
    <div class="container mt-4">
      <div class="row justify-content-center">
        <div class="col-md-8 col-lg-6">
          <div class="card shadow-sm">
            <div class="card-body">
              <h5 class="card-title mb-4 text-center">Print PDF</h5>
              <div class="row g-2 mb-4">
                <div class="col-4 d-grid">
                  <button class="btn btn-secondary" id="getPrinterBtn">Get Printers</button>
                </div>
                <div class="col-8">
                  <select class="form-select" id="printerSelect">
                    <option selected disabled>Select a printer</option>
                  </select>
                </div>
              </div>
              <div class="row g-2 mb-4">
                <div class="col-8">
                  <input type="url" class="form-control" id="urlInput" placeholder="Enter PDF URL" />
                </div>
                <div class="col-4 d-grid">
                  <button class="btn btn-secondary" id="printBtn">Print</button>
                </div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
    <script src="script.js"></script>
  </body>
</html>

And in our script.js

document.addEventListener("DOMContentLoaded", function () {
  // Need to pass our printing extension id here.
  const EXTENSION_ID = "kaoiidjhjcggcngkcafebmlmplnheplp";
  const getPrinterBtn = document.getElementById("getPrinterBtn");
  getPrinterBtn.addEventListener("click", async function () {
    const response = await chrome.runtime.sendMessage(EXTENSION_ID, { key: "CHROME_PRINTING", action: "get_printers" });
    if (response?.action === "get_printers") {
      const printerSelect = document.getElementById("printerSelect");
      printerSelect.innerHTML = "<option selected disabled>Select a printer</option>";
      response.printers.forEach((printer) => {
        const option = document.createElement("option");
        option.value = printer.id;
        option.textContent = printer.name;
        printerSelect.appendChild(option);
      });
    }
  });
  const printBtn = document.getElementById("printBtn");
  const urlInput = document.getElementById("urlInput");
  const printerSelect = document.getElementById("printerSelect");
  printBtn.addEventListener("click", async function () {
    if (urlInput.value && printerSelect.value) {
      const response = await chrome.runtime.sendMessage(EXTENSION_ID, {
        key: "CHROME_PRINTING",
        action: "create_job",
        url: urlInput.value,
        printer_id: printerSelect.value,
        job_id: "test_job_01"
      });
      if (response?.action === "create_job") {
        console.log(response);
      }
    }
  });
});

EXTENSION_ID points to the Chrome extension responsible for handling all printing tasks.

Clicking “Get Printers” sends a request to the extension for all connected printers.

The extension’s response dynamically populates the printer dropdown with printer names and IDs.

This ensures the printer list is always up-to-date, even if devices are added or removed.

Clicking “Print” sends a message to the extension containing:

  • url: The PDF file to print
  • printer_id: The selected printer’s ID
  • job_id: A unique identifier for the print job

The extension processes the print job in the background, while the webpage simply receives a confirmation response.

Building the Chrome OS Extension

In our background.js of the extension.

chrome.runtime.onMessageExternal.addListener(function (request, sender, sendResponse) {
  if (request?.action === "get_printers") {
    chrome.printing.getPrinters().then((printers) => {
      sendResponse({ ext_id: chrome.runtime.id, action: "get_printers", printers: printers });
    });
  } else if (request?.action === "create_job") {
    const printerId = request.printer_id;
    chrome.printing.getPrinterInfo(printerId).then((printerInfo) => {
      const capabilities = printerInfo.capabilities.printer;
      const defaultDpi = capabilities.dpi?.option?.find((d) => d.is_default) || { horizontal_dpi: 300, vertical_dpi: 300 };
      const defaultMedia = capabilities.media_size?.option?.find((m) => m.is_default) || capabilities.media_size.option[0];
      const defaultOrientation = capabilities.page_orientation?.option?.find((o) => o.is_default) || { type: "PORTRAIT" };
      const defaultColor = capabilities.color?.option?.find((c) => c.is_default) || { type: "STANDARD_MONOCHROME" };
      const defaultCollate = capabilities.collate?.default || false;
      const ticket = {
        version: "1.0",
        print: {
          color: { type: defaultColor.type },
          duplex: { type: "NO_DUPLEX" },
          page_orientation: { type: defaultOrientation.type },
          copies: { copies: 1 },
          dpi: { horizontal_dpi: defaultDpi.horizontal_dpi, vertical_dpi: defaultDpi.vertical_dpi },
          collate: { collate: defaultCollate },
          media_size: { width_microns: defaultMedia.width_microns, height_microns: defaultMedia.height_microns }
        }
      };
      fetch(request.url)
        .then((response) => response.arrayBuffer())
        .then((arrayBuffer) => {
          const job = {
            job: {
              printerId: printerId,
              title: request.job_id,
              ticket: ticket,
              contentType: "application/pdf",
              document: new Blob([new Uint8Array(arrayBuffer)], { type: "application/pdf" })
            }
          };
          chrome.printing.submitJob(job).then((response) => {
            if (response !== undefined) sendResponse({ status: response.status });
            else if (chrome.runtime.lastError !== undefined) sendResponse({ message: chrome.runtime.lastError.message });
            else sendResponse({ message: "Something went wrong" });
          });
        });
    });
  } else {
    sendResponse({ ext_id: chrome.runtime.id });
  }
  return true;
});
  • Listens for messages from external webpages using onMessageExternal.
  • "get_printers": Queries all connected printers and returns their details.
  • "create_job": Fetches printer capabilities ( you can edit this to set different options in the printer), builds a dynamic print ticket, fetches the PDF, and submits the print job.
  • Handles success or error responses back to the webpage.
  • Runs continuously as a background worker, separating printing logic from the UI.

In the manifest.json of our extension

{
  "name": "Chrome OS Printing",
  "version": "1.0.1",
  "manifest_version": 3,
  "description": "Chrome OS Printing Extension.",
  "permissions": ["printing"],
  "background": { "service_worker": "background.js" },
  "externally_connectable": { "matches": ["*://*/*"] }
}
  • "permissions": ["printing"] allows access to Chrome OS printing APIs.
  • "background" defines a service worker (background.js) for handling tasks persistently.
  • "externally_connectable" allows any webpage ("*://*/*") to send messages to the extension. You can specify your web page domain to make the extension work only for that page.

This extension and website structure provide a robust and scalable Chrome OS printing solution that can be used in kiosks, enterprise environments, or automated PDF printing workflows.

To read more about Everything You Need to Know About Chrome Extension Development, refer to our blog Everything You Need to Know About Chrome Extension Development.


If you need any assistance in odoo, we are online, please chat with us.



0
Comments



Leave a comment



whatsapp_icon
location

Calicut

Cybrosys Technologies Pvt. Ltd.
Neospace, Kinfra Techno Park
Kakkancherry, Calicut
Kerala, India - 673635

location

Kochi

Cybrosys Technologies Pvt. Ltd.
1st Floor, Thapasya Building,
Infopark, Kakkanad,
Kochi, India - 682030.

location

Bangalore

Cybrosys Techno Solutions
The Estate, 8th Floor,
Dickenson Road,
Bangalore, India - 560042

Send Us A Message