1. Introduction
The Web Printing API brings unprecedented flexibility to implementing printing features in isolated contexts. The API is not exposed in ordinary web contexts.
1.1. Existing alternative
There is a window. method that exists, but it basically
opens a print dialog and asks the user to do the rest. The Web Printing API
gives app developers access to printers locally available to
the operating system directly from the web applications in isolated contexts,
and allows submitting print jobs with custom
print attributes (like paper size, color settings, quality, etc.).print()
1.2. The Web Printing API features
Using the Web Printing API you can:
-
Submit print jobs straight from the code without any dialogs!
-
Implement your own print dialogs!
-
Print with custom print attributes without any user interaction!
-
List printers and fetch their printer capabilities as well as the printer state (idle, busy, etc.). When knowing the printer capabilities, apps can prepare print-ready files with specific print attributes.
-
Automate printing in any way. Build previously repetitive printing workflows.
-
On top of all that, unlike with
window., you can observe the job state of your print jobs - whether they finished, failed, etc.print()
Section 5 of the RFC8011 is especially helpful to learn more (https://datatracker.ietf.org/doc/html/rfc8011#section-5).
2. Examples
2.1. Listing Printers & Basic Attributes
try { const printers= await printing. getPrinters(); for ( const printerof printers) { const attributes= printer. cachedAttributes(); console. log( $attributes { printerName . has the following } basic ( attributes ) $ : attributes { } ); } } catch ( err) { console. warn( "Printing operation failed: " + err); }
2.2. Listing Printers & Detailed Attributes
try { const printers= await printing. getPrinters(); const promises= printers. map( printer=> printer. fetchAttributes()); Promise. all( promises). then(( values) => { for ( const attributesof values) { console. log( $attributes { printerName . has the following } detailed ( attributes ) $ : attributes { } ); } }); } catch ( err) { console. warn( "Printing operation failed: " + err); }
2.3. Querying Printer State
try { const printers= await printing. getPrinters(); const printer= printers. find( printer=> printer. cachedAttributes(). printerName=== 'Brother QL-820NWB' ); const attributes= await printer. fetchAttributes(); console. log( $attributes { printerName . 's } state is $ new attributes { printerState . } ! ); } catch ( err) { console. warn( "Printing operation failed: " + err); }
2.4. Submitting a Print Job
try { const printers= await printing. getPrinters(); const printer= printers. find( printer=> printer. cachedAttributes(). printerName=== 'Brother QL-820NWB' ); const printJob= await printer. submitPrintJob( "Sample Print Job" , new Blob(...), { copies: 2 , media: 'iso_a4_210x297mm' , multipleDocumentHandling: 'separate-documents-collated-copies' , printerResolution: { crossFeedDirectionResolution: 300 , feedDirectionResolution: 400 , units: 'dots-per-inch' }, sides: 'one-sided' , printQuality: 'high' , pageRanges: [{ from : 1 , to: 5 }, { from : 7 , to: 10 }], }); const printJobComplete= new Promise(( resolve, reject) => { printJob. onjobstatechange= () => { const jobState= printJob. attributes(). jobState; if ( IsErrorStatus( jobState)) { console. warn( Job errored$ : jobState { } ); reject( /**/ ); return ; } if ( jobState=== "completed" ) { console. log( "Job complete!" ); resolve( /**/ ); return ; } console. log( Job state changed to $jobState { } ); }; }); await printJobComplete; } catch ( err) { console. warn( "Printing operation failed: " + err); }
2.5. Canceling a Print Job
try { const printers= await printing. getPrinters(); const printer= printers. find( printer=> printer. cachedAttributes(). printerName=== 'Brother QL-820NWB' ); const printJob= await printer. submitPrintJob(...); // This might take no effect if the job has already finished. printJob. cancel(); } catch ( err) { console. warn( "Printing operation failed: " + err); }
3. Extensions to the Window interface
[Exposed =Window ,SecureContext ,IsolatedContext ]partial interface Window { [SameObject ]readonly attribute WebPrintingManager ; };printing
Each Window object is associated with a unique instance of a WebPrintingManager object, allocated when the Window object is created.
4. WebPrintingManager
[Exposed =Window ,SecureContext ,IsolatedContext ]interface {WebPrintingManager Promise <sequence <WebPrinter >>(); };getPrinters
The methods on this interface run some of their steps in parallel, and queue tasks back on the main thread via the web printing task source.
getPrinters() method steps are:
-
If this’s relevant global object’s associated Document is not allowed to use the policy-controlled feature named "web-printing", throw a "
NotAllowedError"DOMException. -
Let promise be a new promise.
-
Let global be this’s relevant global object.
-
Run the following steps in parallel:
-
Let local_printers be all printers locally available to the operating system.
-
Let attributes_list be an empty list of
WebPrinterAttributesdictionaries. -
For each printer of local_printers:
-
Let web_printer_attributes be a new
WebPrinterAttributesdictionary. -
Set web_printer_attributes’s
printerNameto printer’s name. -
Set web_printer_attributes’s
printerIdto printer’s id. The id MUST be obfuscated by returning a hex string representation of a SHA256 hash of itself. -
Append web_printer_attributes to attributes_list.
-
-
Queue a global task on global using the web printing task source to run these steps:
-
Let web_printers be an empty list of
WebPrinterobjects. -
For each attributes of attributes_list:
-
Let web_printer be a new
WebPrinterwhose attributes is set to attributes. -
Append web_printer to web_printers.
-
-
Resolve promise with web_printers.
-
-
-
Return promise.
5. WebPrinter
[Exposed =Window ,SecureContext ,IsolatedContext ]interface {WebPrinter WebPrinterAttributes ();cachedAttributes Promise <WebPrinterAttributes >();fetchAttributes Promise <WebPrintJob >(submitPrintJob USVString ,job_name Blob ,document_data optional WebPrintJobTemplateAttributes = {}); };template_attributes
Each WebPrinter has attributes, which are
an instance of WebPrinterAttributes, initially containing only the
printerName and printerId,
to obtain more, fetchAttributes() needs to be used.
cachedAttributes() method returns the attributes.
fetchAttributes() method steps are:
-
Let promise be a new promise.
-
Run the following steps in parallel:
-
If there is any problem while communicating with the printer, reject promise with a new
NetworkErrorDOMExceptionand abort these steps. -
Let new_web_printer_attributes be a new instance of
WebPrinterAttributes. -
Query the printer for printer capabilities. Let printer_capabilities be a list of returned capabilities.
-
For each printer_capability of printer_capabilities:
-
Perform the necessary mapping to conform the printer_capability with the
WebPrinterAttributesdictionary according to the Internet Printing Protocol (RFC 8011). -
Set the corresponding fields of new_web_printer_attributes with the mapped printer_capability (e.g. printer_capability related to media source should be mapped to valid values of
mediaSourceDefaultandmediaSourceSupported). -
Query the printer for printer state. Set the
printerStateof new_web_printer_attributes to the returned printer state value. -
Set the attributes to new_web_printer_attributes.
-
Resolve promise with new_web_printer_attributes.
-
-
Return promise.
submitPrintJob() method steps are:
-
Let promise be a new promise.
-
Run the following steps in parallel:
-
If there is any problem while communicating with the printer, reject promise with a new
NetworkErrorDOMExceptionand abort these steps. -
Use the algorithm from
fetchAttributes()to update attributes. -
Let printer be an instance of
WebPrinterthesubmitPrintJob()is executed on. -
For each template_attribute of
template_attributes: -
If template_attribute does not contain supported values checked against a corresponding printer’s attributes (e.g.
mediaSourcechecked againstmediaSourceSupported), reject promise with a newDataErrorDOMExceptionand abort these steps. -
Let pdf_data hold a PDF document data. Transform
document_dataBlobto a PDF document and set as value of pdf_data. Ifdocument_datais malformed, i.e. not a valid PDF document, reject promise with a newDataErrorDOMExceptionand abort these steps. -
Send pdf_data alongside with
WebPrintJobTemplateAttributesand submit as a print job to the printer. -
Let print_job be an instance of a
WebPrintJobinterface. Associate print_job with the print job just submitted to the printer.
-
-
Resolve promise with print_job.
-
Return promise.
6. WebPrintJob
[Exposed =Window ,SecureContext ,IsolatedContext ]interface :WebPrintJob EventTarget {WebPrintJobAttributes ();attributes undefined ();cancel attribute EventHandler ; };onjobstatechange
Each WebPrintJob has attributes, which are
an instance of WebPrintJobAttributes, initially empty.
attributes() method returns attributes which shows
the state the print job is in (e.g. how many pages completed).
cancel() method aborts the print job immediately.
signal param of type AbortSignal
passed as a part of the WebPrintJobTemplateAttributes when calling
the submitPrintJob() method.
onjobstatechange is the event handler IDL attribute
for the onjobstatechange event type.
The user agent MUST fire a onjobstatechange event whenever
the WebPrintJobState or jobPagesCompleted of the print job changes.
7. Data model
WebPrinterAttributes - dictionary representing the attributes.
WebPrintJobTemplateAttributes - dictionary representing the print job attributes.
dictionary {WebPrinterAttributes USVString ;printerName USVString ;printerId unsigned long ;copiesDefault WebPrintingRange ;copiesSupported WebPrintingMediaCollection ;mediaColDefault sequence <WebPrintingMediaCollection >;mediaColDatabase USVString ;mediaSourceDefault sequence <USVString >;mediaSourceSupported WebPrintingMimeMediaType ;documentFormatDefault sequence <WebPrintingMimeMediaType >;documentFormatSupported WebPrintingMultipleDocumentHandling ;multipleDocumentHandlingDefault sequence <WebPrintingMultipleDocumentHandling >;multipleDocumentHandlingSupported WebPrintingOrientationRequested ;orientationRequestedDefault sequence <WebPrintingOrientationRequested >;orientationRequestedSupported WebPrintingResolution ;printerResolutionDefault sequence <WebPrintingResolution >;printerResolutionSupported WebPrintColorMode ;printColorModeDefault sequence <WebPrintColorMode >;printColorModeSupported WebPrinterState ;printerState USVString ;printerStateMessage sequence <WebPrinterStateReason >;printerStateReasons WebPrintQuality ;printQualityDefault sequence <WebPrintQuality >;printQualitySupported WebPrintingSides ;sidesDefault sequence <WebPrintingSides >; };sidesSupported dictionary {WebPrintJobTemplateAttributes unsigned long ;copies WebPrintingMediaCollectionRequested ;mediaCol USVString ;mediaSource WebPrintingMultipleDocumentHandling ;multipleDocumentHandling WebPrintingOrientationRequested ;orientationRequested WebPrintingResolution ;printerResolution WebPrintColorMode ;printColorMode WebPrintQuality ;printQuality WebPrintingSides ;sides AbortSignal ; };signal dictionary {WebPrintingRange unsigned long ;from unsigned long ; };to dictionary {WebPrintingResolution unsigned long ;crossFeedDirectionResolution unsigned long ;feedDirectionResolution WebPrintingResolutionUnits ; };units typedef (WebPrintingRange or unsigned long );WebPrintingMediaSizeDimension dictionary {WebPrintingMediaSize WebPrintingMediaSizeDimension ;yDimension WebPrintingMediaSizeDimension ; };xDimension dictionary {WebPrintingMediaCollection USVString ;mediaSizeName WebPrintingMediaSize ; };mediaSize dictionary {WebPrintingMediaSizeRequested required unsigned long ;yDimension required unsigned long ; };xDimension dictionary {WebPrintingMediaCollectionRequested required WebPrintingMediaSizeRequested ; };mediaSize dictionary {WebPrintJobAttributes USVString ;jobName unsigned long ;jobPages unsigned long ;jobPagesCompleted WebPrintJobState ; };jobState enum {WebPrintingMimeMediaType , };"application/pdf" enum {WebPrintingMultipleDocumentHandling ,"separate-documents-collated-copies" , };"separate-documents-uncollated-copies" enum {WebPrintingOrientationRequested ,"portrait" , };"landscape" enum {WebPrintingResolutionUnits ,"dots-per-inch" , };"dots-per-centimeter" enum {WebPrintingSides ,"one-sided" ,"two-sided-long-edge" , };"two-sided-short-edge" enum {WebPrintQuality ,"draft" ,"normal" , };"high" enum {WebPrintColorMode ,"color" , };"monochrome" enum {WebPrinterState ,"idle" ,"processing" , };"stopped" enum {WebPrinterStateReason ,"none" ,"other" ,"connecting-to-device" ,"cover-open" ,"developer-empty" ,"developer-low" ,"door-open" ,"fuser-over-temp" ,"fuser-under-temp" ,"input-tray-missing" ,"interlock-open" ,"interpreter-resource-unavailable" ,"marker-supply-empty" ,"marker-supply-low" ,"marker-waste-almost-full" ,"marker-waste-full" ,"media-empty" ,"media-jam" ,"media-low" ,"media-needed" ,"moving-to-paused" ,"opc-life-over" ,"opc-near-eol" ,"output-area-almost-full" ,"output-area-full" ,"output-tray-missing" ,"paused" ,"shutdown" ,"spool-area-full" ,"stopped-partly" ,"stopping" ,"timed-out" ,"toner-empty" ,"toner-low" , };"cups-pki-expired" enum {WebPrintJobState ,"preliminary" ,"pending" ,"processing" ,"completed" ,"canceled" };"aborted"
8. Privacy & Security Considerations
8.1. Potential issues
8.1.1. Fingerprinting
The WebPrinter object exposes printerName and printerId
attributes that can be used for fingerprinting.
8.1.2. Forging print jobs
Malicious code injection could lead to:
-
unwanted print jobs being submitted to the printer,
-
denial of service attack on printers .
This MUST never happen in isolated context.
8.1.3. Surveillance
Applications could potentially observe when printers are in use.
8.2. Mitigating factors
8.2.1. Permissions Policy
This specification defines a policy-controlled feature identified by
the string "web-printing".
Its default allowlist is "self".
A document’s permissions policy determines whether
any content in that document is allowed to use getPrinters(). If disabled
in any document, no content in the document will be allowed to use
getPrinters().
8.2.2. User Consent
Access to printers is a powerful feature. A user agent MUST NOT allow
a web application to gain access to a WebPrinter object without
express permission.
User consent MUST be obtained for a specific origin.
The request for consent MUST be triggered by a call to the
getPrinters() method. The user agent MUST display
a permission promptthat clearly indicates which origin is requesting access
and provides the user with enough information to make an informed decision.
User agents SHOULD provide options for both transient (e.g., "for this session only") and persistent permission. To mitigate the risk of users forgetting they have granted persistent access, transient permission SHOULD be the default and more prominent option.
Users MUST be provided with a mechanism to view and revoke any previously granted permissions for this API.