Convert Google Docs to HTML

Updated February 17, 2026

If you publish content online, you've probably felt the friction of working in platform editors. Writing in WordPress's block editor, formatting a post in Substack, or building an email in Kit can feel clunky compared to the tool where you do most of your actual thinking and writing: Google Docs. The keyboard shortcuts are second nature, the collaboration features are unmatched, and the formatting toolbar does exactly what you expect. But when it's time to move that content to your publishing platform, the pain starts. You copy, you paste, and then you spend the next twenty minutes re-adding headings, fixing broken links, reformatting code blocks, and wondering why your bullet lists look wrong. There has to be a better way.

There is: convert your Google Docs directly to clean HTML. In this tutorial, I'll show you how to build a Google Docs-to-HTML converter powered by Apps Script, with a Google Sheets dashboard to manage your documents and a one-click preview that renders the output right inside a modal dialog.

Document converting to HTML code, shown with arrow indicating the transformation.

The converter handles headings, bold and italic text, links, lists, images, tables, and even styled callout boxes. You write in Google Docs using the formatting tools you already know, and the script transforms it into HTML that's ready to use anywhere.

What makes this approach especially powerful is its extensibility. The HTML output from this converter can be sent anywhere that accepts content via an API. You could publish it to WordPress, push it to a static site hosted on GitHub or Render, pipe it into an email newsletter service like Kit or Mailchimp, or post it to a custom CMS. Google Sheets and Google Docs become the content management system, and the converter is the bridge between your writing and whatever platform you choose.

In this tutorial, I'll focus on the converter itself and the preview workflow. Publishing to external platforms is a natural next step that you can add later. That said, the subscriber-exclusive template linked below provides a way to copy and paste the formatted HTML into your favorite publishing platform. Here's a screenshot of content that I pasted into Substack:

Screenshot of a blog post about Google Apps Script with social sharing icons.
Newsletter Subscriber Exclusive

Google Docs to HTML Converter: Ready-to-Use Template

As a valued newsletter subscriber, you can get a ready-to-use template for the Google Docs to HTML Converter. This template includes a pre-configured Google Sheet with the CMS dashboard and the full Apps Script converter already installed.

By subscribing, you agree to our Privacy Policy and Terms of Service

Already a subscriber? Log in

Prerequisites

This tutorial assumes the following prerequisites:

  • A Google account with access to Google Sheets, Google Docs, and Google Apps Script
  • Basic familiarity with Google Apps Script (see Getting started with Apps Script)
  • Basic understanding of HTML

4 steps to convert Google Docs to HTML

Step 1 — Set up the management spreadsheet

The spreadsheet serves as your content dashboard. Each row represents a document you want to convert, and the columns store the metadata the script needs to find and process it.

Create a new Google Sheet and rename the first tab to Posts. Add the following column headers in row 1:

Column

Header

Description

A

Title

The display title of your document

B

Description

A short summary of the content

C

URL Slug

A URL-friendly identifier (e.g., my-first-post)

D

Tags

Comma-separated tags for categorization

E

Doc ID

The Google Doc ID containing the content

Screenshot of a Google Sheet titled 'Simple Content Management System' with sample data.

Step 2 — Add the converter script

The converter script is a bound script attached to your Google Sheet. It reads the Doc ID from the selected row, opens the corresponding Google Doc, converts its content to clean HTML, and displays the rendered output in a modal dialog.

Open your spreadsheet and go to Extensions > Apps Script. Delete any existing code in the editor and paste the full script provided in the "Full code" section at the end of this tutorial. Save the project and close the script editor.

When you reload the spreadsheet, you'll see a new Docs to HTML menu in the menu bar. This menu is created by the onOpen() function, which runs automatically each time the sheet opens. The menu provides a single action: Preview Selected Row, which converts the Google Doc in the selected row and shows the result.

Screenshot of a spreadsheet program interface with a menu bar and formatting toolbar.

Let me walk through how the converter works, since it's the core of this tutorial. The conversion starts with the processBody() function, which iterates through every element in the document body. Each element is handled according to its type: paragraphs are converted based on their heading level (Heading 1 becomes an h1 tag, Heading 2 becomes an h2, and so on), list items are collected into ul tags, and tables receive special treatment.

The most interesting part is the processTextElement() function, which handles character-level formatting. It loops through every character in a text element, tracking whether bold, italic, code, or link formatting is currently active. When formatting changes between characters, it opens or closes the appropriate HTML tags. This character-level approach ensures that mixed formatting like "a bold word in a sentence" converts correctly, even when multiple styles overlap.

Tables get special handling based on their structure. A standard multi-row table is converted to an HTML table element. But single-cell tables are treated as special content blocks: if the cell has a light blue background, it becomes an informational note; light yellow becomes a tip; light red becomes a warning; gray becomes a neutral note; and white or transparent backgrounds are treated as code blocks. This convention lets you create styled callout boxes in your posts using nothing but native Google Docs table formatting.

The following table summarizes the color-to-callout mapping:

Background Color

Hex Code

Output Class

Light blue

#cfe2f3

note (informational)

Light yellow

#fff2cc

tip

Light red

#f4cccc

warning

Light gray

#f3f3f3

note-gray (neutral)

White / none

pre > code (code block)

The preview modal is built by the previewSelectedRow() function. It wraps the converted HTML in a minimal page shell with clean typography styles, then passes it to SpreadsheetApp.getUi().showModalDialog(). The result is a live, rendered preview of your post that appears right inside Google Sheets. You can see exactly how your headings, formatting, notes, and tables will look before you use the HTML anywhere else.

Step 3 — Write content in Google Docs

Now it's time to write your content. Create a new Google Doc and use standard formatting. The converter supports the following elements:

  • Headings: Use Heading 1 through Heading 4 from the toolbar. These map directly to h1 through h4 tags.
  • Bold and italic: Standard formatting is preserved as strong and em tags.
  • Links: Hyperlinked text is converted to anchor tags with target="_blank".
  • Bullet lists: Bulleted lists become unordered list elements. Numbered lists and nested lists are not currently supported.
  • Tables: Multi-row tables are converted to standard HTML tables with th headers.
  • Code blocks: Single-cell tables with a white background are treated as pre/code blocks.
  • Styled notes: Single-cell tables with colored backgrounds become styled callout divs.
  • Inline code: Text formatted in Courier New or Consolas is wrapped in code tags.

Once your Doc is written, copy its Doc ID from the URL bar and paste it into the Doc ID column of your spreadsheet. Fill in the Title, Description, URL Slug, and Tags columns for the row.

Step 4 — Preview the rendered HTML

With your content in place, select the row in your spreadsheet that contains the Doc ID you want to preview. Then click Docs to HTML > Preview Selected Row from the menu bar.

The first time you run the script, Google will ask you to authorize it. This is expected. The script needs permission to read your Google Docs and display UI elements in Sheets. Review the permissions and click Allow.

After authorization, a modal dialog will open showing a fully rendered preview of your converted HTML. The preview includes clean typography, styled note blocks, formatted code, and all the headings and inline formatting from your original document. It's a live representation of what your HTML will look like when used on a website or in any other context.

Screenshot of Google Sheets with a 'Getting Started with Apps Script' tutorial overlay.

If the preview doesn't look right, go back to your Google Doc, adjust the formatting, and run the preview again. The conversion happens fresh each time, so changes are reflected immediately.

Full code

The complete script is below. Copy the entire block into your spreadsheet's Apps Script editor (Extensions > Apps Script).

Newsletter Subscriber Exclusive

Complete Converter Script

This section is exclusively available to newsletter subscribers. Subscribe below to access it.

By subscribing, you agree to our Privacy Policy and Terms of Service

Already a subscriber? Log in

Limitations

There are a few things the converter does not handle that are worth knowing about before you start writing.

The most significant limitation is images. Google Docs stores all inline images as embedded blobs, regardless of how they were inserted. Apps Script provides no way to extract an image's raw bytes and host them at a public URL. The converter reads the image's link URL property, but this is only populated if you've explicitly added a hyperlink to the image itself. To make images work with the converter, host your images separately, insert them into your Doc however you like, then right-click each image, select Link, and paste the hosted URL. The converter will use that link as the image's src attribute. Without this step, images fall back to a placeholder.

The converter also does not support ordered (numbered) lists. All list items are converted to unordered lists with <ul> tags, regardless of whether the Google Doc uses bullets or numbers. If numbered lists are important to your content, this would require extending the processListItem() function to check the list item's glyph type.

Nested lists are flattened. A bulleted list with sub-items in the Google Doc will render as a flat, single-level list in HTML. The converter does not track indentation or nesting level.

Other formatting features that are not preserved include strikethrough, underline, text color, highlight color, and footnotes. The converter focuses on the structural and semantic formatting that matters most for web content: headings, bold, italic, links, code, lists, tables, and callout blocks.

These limitations are intentional trade-offs to keep this tutorial from becoming too complex. Each one can be addressed by extending the relevant processing function if your workflow requires it.

How the code works

The script has three logical layers: the menu and preview UI, the document-to-HTML converter, and a set of utility functions for HTML encoding. Each subsection below explains a key function. Click to expand.

The onOpen function and custom menu

The onOpen() function is a special Apps Script trigger that runs automatically whenever the spreadsheet is opened. It creates a custom menu called "Docs to HTML" with a single item: "Preview Selected Row". This gives you a clean, one-click workflow without needing to open the script editor. The menu calls previewSelectedRow() when clicked.

The previewSelectedRow function

This is the main entry point. When you click the menu item, previewSelectedRow() reads the currently selected row and extracts the Title, Description, Tags, and Doc ID from the appropriate columns. It finds columns by header name rather than hard-coded indices, so column order doesn't matter. It then calls convertDocToHTML() to transform the linked Google Doc, wraps the result in a styled page shell via buildPreviewPage(), and displays it in a modal dialog using showModalDialog(). Errors during conversion are caught and shown as alert dialogs.

The processBody function

This function is the core of the converter. It iterates through every child element in the document body and dispatches each one to the appropriate handler: paragraphs go to processParagraph(), list items to processListItem(), and tables to processTable(). It also manages list state. When consecutive list items appear, they're grouped inside a single <ul> tag, and the tag is closed as soon as a non-list element appears.

The processTextElement function

This is where the character-level formatting happens. The function loops through every character in a text element, checking four properties at each position: whether the character is bold, italic, part of a link, or formatted in a monospace font (indicating inline code). When any property changes from one character to the next, the function opens or closes the corresponding HTML tag. This approach handles overlapping styles correctly. For example, if a word is both bold and a link, the function emits <a><strong> at the start and closes both tags at the end.

The processTable function

Tables use a branching strategy. If the table has exactly one row with one cell, it's treated as a special block: the cell's background color determines whether it becomes a note (blue), tip (yellow), warning (red), gray note, or code block (white/default). Multi-row tables are converted to standard HTML table elements, with the first row's cells wrapped in <th> tags and subsequent rows in <td> tags.

Conclusion

In this tutorial, you built a Google Docs-to-HTML converter that transforms formatted documents into HTML. You set up a Google Sheets dashboard to manage your documents, wrote a converter script that handles headings, inline formatting, links, lists, tables, and styled callout blocks, and created a one-click preview workflow that renders the output in a modal dialog.

The converter produces HTML that's ready to use in any context: a blog, a CMS, an email template, or a static site. Because the conversion logic is separate from any publishing mechanism, you can plug it into any workflow or platform that fits your needs.

Key Takeaway

The architecture is intentionally modular. The spreadsheet manages metadata, the converter transforms content, and the preview validates output. Each piece can be extended or replaced independently, which is what makes this approach so adaptable.

Thank you for reading. I hope this tutorial helps you think about Google Docs as a content authoring tool that goes well beyond its native export capabilities.

DISCLAIMER: This content is provided for educational purposes only. All code, templates, and information should be thoroughly reviewed and tested before use. Use at your own risk. Full Terms of Service apply.