Skip to main content

· Workflow · 6 min read

How to Self-Host Google Fonts: Download, Convert, and Write @font-face

Move a Google Font from the hosted API to your own server: download the files, convert them to WOFF2, write the @font-face rules, and remove the old links.

The quickest way to use a Google Font is to paste the <link> tags from the Google Fonts site. The alternative is to put the font files on your own server and write the CSS yourself. This guide walks through that switch, step by step, and ends with a check that nothing still loads from Google.

Why people self-host Google Fonts

Fewer third parties. With the hosted service, every visitor’s browser requests a stylesheet from fonts.googleapis.com and font files from fonts.gstatic.com. Like any server, Google’s receives basic request information such as the visitor’s IP address. Self-hosting removes those requests entirely. Some site owners do it for privacy reasons or to keep their list of third-party services short. Whether your site is required to do so is a legal question that depends on where you operate; this guide does not answer it.

Control. Your files only change when you change them, you set your own cache headers, and your content security policy needs no extra font origins.

Performance, with a caveat. Self-hosting saves the connections to two extra hosts. The old argument for the hosted service, that visitors probably had the font cached from another site, no longer holds: browsers now keep a separate cache per site, as Chrome explains in Gaining security and privacy by partitioning the cache. On the other hand, Google serves small files split by script, and web.dev’s Best practices for fonts notes that self-hosting is not automatically faster. Measure before and after.

Check the license

The Google Fonts FAQ explains that the fonts are open source, mostly under the SIL Open Font License, with some under the Apache License or the Ubuntu Font License, and that they can be used in commercial projects. Each download includes its license file. Read it and keep it with the font files in your project. If you plan to modify a font, for example by subsetting it, check what the license says about modified versions.

Step 1: Download the font files

On the family’s page on fonts.google.com, use the download option to get a ZIP of the family. The same files are also published in the google/fonts repository on GitHub.

For a variable family, the ZIP typically contains one or two variable font files (their names include VariableFont), a static folder with one file per style, and the license file, such as OFL.txt. Decide which you need:

  • The variable files if you use several weights. One file covers the whole range; Variable fonts on the web explains how to use it.
  • A few static files if you only use one or two weights. They can be smaller in total.

Open the files you picked in the font viewer to confirm the name, weight or weight range, and the characters each one includes.

Step 2: Convert to WOFF2 and trim the characters

The downloaded files are TTF. Convert each one to WOFF2 with the TTF to WOFF2 converter. It runs in your browser, and the web font kit includes an @font-face rule to start from.

One difference from the hosted service is worth knowing. Google’s API splits each family into smaller files by script, such as Latin, Cyrillic, or Greek, and the browser downloads only the ones a page uses. The TTF in the ZIP contains every character the family supports. If your site only needs Latin characters, subsetting the file brings it closer to what Google would have served; How to subset a web font shows how. FontPivot’s font subsetter does it in your browser: its default character set is the same as Google’s Latin subset, and its “Split like Google Fonts” option makes one file per script (Latin, Latin Extended, Vietnamese, Cyrillic, Greek, and the rest), each with its own unicode-range.

Step 3: Write the @font-face rules

Give your @font-face rules the same font-family name the Google stylesheet used. Then every existing font-family declaration in your CSS keeps working without changes.

For a variable family with a separate italic file:

/* fonts.css — "Brand Sans" stands for your family's name */
@font-face {
  font-family: 'Brand Sans';
  src: url('/fonts/brand-sans-variable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Brand Sans';
  src: url('/fonts/brand-sans-italic-variable.woff2') format('woff2');
  font-weight: 100 900;
  font-style: italic;
  font-display: swap;
}

Use the weight range the font viewer shows for your file; 100 900 is only an example.

For two static weights:

@font-face {
  font-family: 'Brand Sans';
  src: url('/fonts/brand-sans-regular.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Brand Sans';
  src: url('/fonts/brand-sans-bold.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

The display=swap parameter you may have had in the Google Fonts URL no longer applies; font-display in your own rules replaces it. Choosing a font-display value explains the options. How to self-host a custom font covers file paths, caching headers, and CORS in more detail.

Step 4: Remove the Google Fonts tags

Delete the tags you pasted from Google Fonts. They usually look like this:

<!-- Remove these -->
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
<link href="https://fonts.googleapis.com/css2?family=Brand+Sans&display=swap" rel="stylesheet" />

Also search your stylesheets for an @import of fonts.googleapis.com, and your templates, themes, and plugins for any other reference. Then load your own stylesheet instead:

<link rel="stylesheet" href="/css/fonts.css" />

Step 5: Preload the main file

Your fonts now come from your own server, so a preload hint can start the most important download early. Preload only the file used by the first screen of text, usually the regular weight or the variable file:

<link rel="preload" href="/fonts/brand-sans-variable.woff2" as="font" type="font/woff2" crossorigin />

The crossorigin attribute is required even on your own domain. How to preload web fonts explains why, and when not to preload.

Step 6: Check that nothing still calls Google

  1. Open your browser’s developer tools, go to the Network panel, and reload with the cache disabled.
  2. Type fonts.g into the filter. No requests to fonts.googleapis.com or fonts.gstatic.com should appear.
  3. Filter by “Font” and check that your own WOFF2 files load with status 200.
  4. Repeat on each kind of page: home, article, checkout, and any page with embedded widgets. Third-party embeds and plugins can load Google Fonts on their own.

Shortcuts for frameworks and package managers

If you use a build tool, you may not need to do this by hand:

  • Next.js: next/font/google downloads the CSS and font files at build time and serves them with your site; according to its documentation, no requests are sent to Google by the browser.
  • npm: Fontsource publishes open-source fonts, including Google Fonts families, as npm packages you can self-host.

Both still deserve the same final check in the Network panel.

Checklist

Self-hosting Google Fonts
[ ] License file read and kept with the fonts
[ ] Variable or static files chosen; only the styles you use
[ ] Files converted to WOFF2 (and subset if you only need some scripts)
[ ] @font-face rules use the same family name as before
[ ] font-weight ranges or values match the files
[ ] font-display set in your own rules
[ ] Google Fonts <link> and @import tags removed everywhere
[ ] Main file preloaded with crossorigin
[ ] Network panel shows no fonts.googleapis.com or fonts.gstatic.com requests

Further reading

Share:
Back to guides

Related guides

All guides »