How to Query Local Fonts Using Font Access API

The Font Access API provides web applications with the ability to discover and access the full catalog of locally installed fonts on a user’s operating system. By utilizing the window.queryLocalFonts() method in JavaScript, developers can programmatically enumerate system fonts, inspect their metadata, and retrieve raw binary font data. This guide explains the technical workflow of the API, including permission management, font enumeration, filtering options, and accessing raw SFNT font tables.

Security and Permission Requirements

Because enumerating local fonts can introduce fingerprinting risks, the Font Access API is restricted to secure contexts (HTTPS) and requires explicit user consent.

Before querying fonts, the browser prompts the user for permission. You can check or request permissions programmatically using the Permissions API:

const { state } = await navigator.permissions.query({ name: 'local-fonts' });

if (state === 'granted' || state === 'prompt') {
  // Permission is either already granted or will trigger a prompt upon calling the API
}

Enumerating All Local Fonts

The core method of the API is window.queryLocalFonts(). When called, it requests permission if not already granted and resolves to an array of FontData objects representing the installed fonts.

async function getInstalledFonts() {
  try {
    const availableFonts = await window.queryLocalFonts();
    
    for (const font of availableFonts) {
      console.log(`PostScript Name: ${font.postscriptName}`);
      console.log(`Full Name: ${font.fullName}`);
      console.log(`Family: ${font.family}`);
      console.log(`Style: ${font.style}`);
    }
  } catch (err) {
    console.error(`Error querying fonts: ${err.name}, ${err.message}`);
  }
}

Each FontData object exposes standard metadata properties: * postscriptName: The unique identifier used to target the font in PostScript contexts. * fullName: The complete name of the font (e.g., “Helvetica Bold”). * family: The overarching font family (e.g., “Helvetica”). * style: The specific style variant (e.g., “Bold”, “Italic”).

Filtering Specific Fonts

Querying the entire font registry can yield thousands of entries, which can impact performance. If your application only requires specific fonts, you can pass a postscriptNames filter to the query method:

async function getSpecificFonts() {
  const specificFonts = await window.queryLocalFonts({
    postscriptNames: ["Verdana", "Verdana-Bold", "ArialMT"]
  });

  return specificFonts;
}

Accessing Low-Level Binary Data

Beyond reading font metadata, advanced graphics and design tools often require access to raw OpenType/TrueType tables. The FontData object provides a blob() method that returns a Promise resolving to a Blob containing the complete font file:

async function parseFontTable(fontData) {
  // Retrieve the binary SFNT data
  const sfntBlob = await fontData.blob();
  
  // Convert blob to ArrayBuffer for custom parsing or WebAssembly processing
  const arrayBuffer = await sfntBlob.arrayBuffer();
  
  return arrayBuffer;
}

This binary access enables client-side rendering engines, layout engines, and WebAssembly modules to parse glyph data, OpenType features, and metrics directly within the browser without requiring external server-side font hosting.