Document Automation Made Simple

How to Embed Fonts in PDF from HTML and Keep Real Font Names

Web fonts from Google Fonts often turn into Type 3 fonts when HTML is printed to PDF, so Word and PowerPoint lose your font weights. See why it happens, how to embed static fonts with their real names, and how to fix pages you don't control with UserCss. Real sample files included.

Tomas, CEO

Short answer: to embed fonts in a PDF made from HTML and keep their real names, give the browser one static font file per weight. With Google Fonts, that means one request per weight, such as wght@400 and wght@700, not one request for all of them. If you request several weights at once, the PDF ends up with Type 3 fonts that are all called "Regular".

Many teams convert in two steps. First they turn HTML or a web page into a PDF with the HTML to PDF API or their own tool. Then they convert that PDF to an editable document with the PDF to Word API or the PDF to PowerPoint API. This second step reads the font names stored in the PDF to decide which font each piece of text uses.

If the PDF says "Roboto-Light", Word gets Roboto Light. A font's weight is how thick its letters are, from Thin (100) to Black (900). If every weight in the PDF is called "Roboto-Regular", Word cannot tell Light from Medium or Black, and only Regular and Bold remain. This guide shows why that happens and how to fix it.

Why Do Web Fonts Become Type 3 Fonts in PDF?

Most modern web fonts are variable fonts: one file that holds every weight from Thin to Black. Google Fonts serves a variable file whenever one request asks for more than one weight:

<!-- Each of these loads one variable font file -->
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300;400;500;700&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@100..900&display=swap" rel="stylesheet">

Chrome cannot embed a variable font as a normal font when it prints to PDF. Tools built on Chrome, such as Puppeteer and Playwright, behave the same way. Chrome writes the text as Type 3 fonts instead. A Type 3 font stores each letter as a small drawing, not as a real font, and Chrome names every weight after the font's default style. Our four-weight sample page produced seven fonts, all named the same:

name                    type
AAAAAA+Roboto-Regular   Type 3
BAAAAA+Roboto-Regular   Type 3
CAAAAA+Roboto-Regular   Type 3
...

The PDF still looks right on screen. The problem appears in the next step. Converted to Word, every line becomes plain "Roboto", and only a bold flag survives for the heaviest weights. Light and Medium are gone, and Type 3 text also gets extra spaces, so "12" turned into "1 2" in our sample.

Before: the PDF made with one Google Fonts request for all weights. Word shows plain "Roboto" for the Light text, and the pallet counts read "1 2" and "1 5".

Word after PDF to Word conversion of the Type 3 PDF: the font box shows Roboto for Light text, and the numbers 12 and 15 are split into 1 2 and 1 5

After: the PDF made with one request per weight. Word shows "Roboto Light", and the numbers are intact.

Word after PDF to Word conversion of the TrueType PDF: the font box shows Roboto Light for the same text

How to Embed Fonts in PDF Correctly: One Static File per Weight

Give the browser a static font file for each weight you use. A static font file contains only one weight. Static files are embedded as real TrueType fonts with their real names. TrueType is the normal way a PDF stores a font:

name                    type
AAAAAA+Roboto-Bold      CID TrueType
BAAAAA+Roboto-Light     CID TrueType
CAAAAA+Roboto-Medium    CID TrueType
DAAAAA+Roboto-Regular   CID TrueType

Word then shows Roboto Light, Roboto, Roboto Medium and bold Roboto, exactly as designed.

Fonts in the PDF and in Word: one Google Fonts request for all weights gives Type 3 Roboto-Regular, one request per weight gives TrueType Roboto-Light, Regular, Medium and Bold

With Google Fonts: One Request per Weight

Google serves a static file when a request asks for a single weight. So request each weight on its own line:

<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@300&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@400&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@500&display=swap" rel="stylesheet">
<link href="https://fonts.googleapis.com/css2?family=Roboto:wght@700&display=swap" rel="stylesheet">

Do not combine them into one URL, not even as separate family= parameters. Any request that names more than one weight gets the variable file again.

With Self-Hosted Fonts

If you host fonts yourself, use the static files. Most font downloads keep them in a static/ folder. Write one @font-face rule per weight:

@font-face { font-family: "Roboto"; font-weight: 400; src: url(/fonts/Roboto-Regular.woff2) format("woff2"); }
@font-face { font-family: "Roboto"; font-weight: 700; src: url(/fonts/Roboto-Bold.woff2) format("woff2"); }

What Else Turns Fonts into Type 3?

Three more things produce Type 3 fonts, so avoid them:

  • Missing weights. If you only provide Regular but use bold text, the browser fakes the bold, and fake bold is Type 3. Headings are bold by default, so this happens often. Provide a file for every weight you use. Word loses bold completely in this case.
  • OTF files with CFF outlines. Prefer TrueType-based .ttf or .woff2 files.
  • Fonts with restricted embedding licenses. The font file itself forbids normal embedding.

How to Change Fonts on a Website You Don't Control

This part is for developers who call the API.

When you convert a live website, you cannot edit its HTML. Use the UserCss parameter to add the static fonts and apply them to the page:

@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@400&display=swap');
@import url('https://fonts.googleapis.com/css2?family=Roboto:wght@700&display=swap');

body, h1, h2, h3, p, li, td, th, span, a {
  font-family: 'Roboto', sans-serif !important;
}

Save that CSS as usercss.css and send it with the conversion:

curl -F "Url=https://www.example.com/your-page" -F "UserCss=<usercss.css" -F "ConversionDelay=3" -F "StoreFile=true" -H "Authorization: Bearer api_token" https://v2.convertapi.com/convert/html/to/pdf

Or in C# with the ConvertAPI .NET library:

var result = await convertApi.ConvertAsync("html", "pdf",
    new ConvertApiParam("Url", "https://www.example.com/your-page"),
    new ConvertApiParam("UserCss", "@import url(\"https://fonts.googleapis.com/css2?family=Roboto:wght@400&display=swap\");@import url(\"https://fonts.googleapis.com/css2?family=Roboto:wght@700&display=swap\");body,h1,h2,h3,p,li,td,th,span,a{font-family:\"Roboto\",sans-serif !important}"),
    new ConvertApiParam("ConversionDelay", "3"));

Follow three rules:

  1. Import every weight the page uses, one @import each. If the page also uses 300 or 500, import those too. Any weight you leave out still comes from the page's own variable font and ends up as Type 3.
  2. Add !important to the font-family rules, and list the elements that set their own font. Without it, class rules and inline styles on the page win. Don't put !important inside @font-face rules, because that drops the font.
  3. Set ConversionDelay to 2 or 3 seconds, so the injected fonts finish loading before the PDF is created.

Some websites block injected styles or external fonts with a Content Security Policy. On those sites UserCss has no effect.

How to Check Which Fonts Are Embedded in a PDF

Check the fonts before you convert the PDF with the PDF to Word API or the PDF to PowerPoint API:

  • Adobe Acrobat: open File > Properties and select the Fonts tab.

Before: one request for all weights. Acrobat lists only Type 3 fonts named T3Font_0, T3Font_1 and so on, so the real font names are gone.

Before: Adobe Acrobat font properties listing Type 3 fonts T3Font_0, T3Font_1 and T3Font_2

After: one request per weight. Acrobat lists Roboto-Light, Roboto-Regular, Roboto-Medium and Roboto-Bold as embedded TrueType (CID) fonts.

After: Adobe Acrobat font properties listing Roboto-Light, Roboto-Regular, Roboto-Medium and Roboto-Bold as embedded TrueType (CID) fonts

  • Command line: run pdffonts output.pdf from the free poppler tools.

You want only TrueType or CID TrueType entries with the right weight names. These are the normal font types in a PDF. Also check that every font is embedded: pdffonts shows yes in the emb column, and Acrobat shows "Embedded" or "Embedded Subset" after the name. Any Type 3 entry, shown as T3Font_0 or T3Font_1 in Acrobat, means the page still uses a variable font or misses a weight.

Try It Yourself: Download the Sample Files

We ran one sample page through the HTML to PDF API and the PDF to Word API. These are the actual outputs:

Frequently Asked Questions

How do I embed fonts in a PDF created from HTML?

Load a static font file for every weight the page uses. With Google Fonts, request each weight separately, for example wght@400 and wght@700. The browser then embeds them as TrueType fonts with their real names.

What are Type 3 fonts in a PDF?

Type 3 fonts store each character as a drawing instead of a normal font program. The text still looks right, but the PDF loses the font's real name and weight. Chrome-based tools write variable web fonts and fake bold text as Type 3.

Why does my PDF show T3Font_0 or T3Font_1?

That is how Adobe Acrobat lists Type 3 fonts. It usually means the page used a variable web font, for example Google Fonts with several weights in one request.

Why does Word lose my font weights after PDF to Word conversion?

Word reads the font names stored in the PDF. If every weight is stored as "Roboto-Regular", only the family name and a bold flag survive. Embed static fonts with real names, and Word keeps Light, Medium and Black.

Can I change the fonts of a website I don't control?

Yes. Send CSS in the UserCss parameter of the HTML to PDF API with one @import per weight and !important on the font-family rules. Add a ConversionDelay of 2 to 3 seconds so the fonts finish loading.

Conclusion

Variable web fonts look the same in the browser, but they lose their names when printed to PDF. Static fonts, one file per weight, keep them. Get that right in the HTML step, and the PDF to Word and PDF to PowerPoint conversions keep your typography intact.

Generating invoices or reports from HTML templates? See how to generate dynamic documents at scale, or read the guide to converting HTML to PDF with PHP.


Related converters

Ready to Streamline Your File Conversions?