GEO Report PDF Renderer
Render a GEO audit markdown file into a styled client-ready PDF with a cover page, color-coded score tables, and severity callouts
A markdown audit is a file. A PDF with a navy cover page and a color-coded score badge is a deliverable you can charge for. This playbook converts one into the other with pandoc and headless Chrome, no Python and no design work.
Who it's for: GEO and SEO agencies sending client deliverables, freelance consultants, marketing teams presenting to executives, anyone who needs an audit to look like a report
Example
"Turn GEO-AUDIT-REPORT.md into a PDF" → GEO-REPORT.pdf with a dark navy cover carrying the brand name, domain, and score badge, score cells shaded green through red by value, severity-tagged finding callouts, automatic section page breaks, and page-numbered footers
New here? 3-minute setup guide → | Already set up? Copy the template below.
# GEO PDF Report Generator
Turn a finished GEO audit markdown file into a styled, client-ready PDF using pandoc plus headless Chrome. No Python, no ReportLab, no JSON wrangling.
## Prerequisites
- **pandoc** — `brew install pandoc` (macOS), `choco install pandoc` or `winget install JohnMacFarlane.Pandoc` (Windows), `apt install pandoc` (Debian/Ubuntu)
- **Google Chrome or Chromium** — used in headless mode to print HTML to PDF
Find the Chrome binary once and reuse the path:
| OS | Typical path |
|---|---|
| macOS | `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome` |
| Windows | `C:\Program Files\Google\Chrome\Application\chrome.exe` |
| Linux | `google-chrome` or `chromium` on `PATH` |
## Input
A markdown audit report in the current folder, named `GEO-AUDIT-REPORT.md` by default. If no such file exists, stop and tell the user to produce the audit report first. Do not fabricate audit data to fill the PDF.
## Styling assets
The upstream geo-seo-claude suite ships a pandoc HTML template and stylesheet that produce the dark navy cover and score badge. Running as a standalone CLAUDE.md, you will not have those files. On the first run, generate them into a local `geo-pdf/` folder in the current directory:
- `geo-pdf/template.html` — a pandoc HTML5 template containing the cover section, the metadata variables listed below, and an inline `<script>` that post-processes the document before printing
- `geo-pdf/style.css` — typography, table styling, page footer, and `@page` rules
Reuse those files on later runs instead of regenerating them.
## Workflow
### Step 1: Check for the audit report
Look for `GEO-AUDIT-REPORT.md` in the current directory. If absent, stop.
### Step 2: Extract cover metadata
Read the top of the report and pull these fields:
| Field | Where to find it |
|---|---|
| `brand_name` | First H1 title, after "GEO Audit Report:" |
| `domain` | Second bold line, e.g. `**Domain:** example.com` |
| `geo_score` | Line matching `## Overall GEO Score: XX / 100` |
| `score_label` | The word after the score on that same line, e.g. "Poor", "Fair", "Good" |
| `date` | `**Audit Date:**` line |
| `business_type` | `**Business Type:**` line |
| `locations` | `**Locations:**` line |
| `platform` | `**CMS:**` line |
If a field is missing, omit its `--metadata` flag and let the template fall back to its default.
### Step 3: Run pandoc
```bash
pandoc GEO-AUDIT-REPORT.md \
--to html5 \
--standalone \
--embed-resources \
--template geo-pdf/template.html \
--css geo-pdf/style.css \
--metadata title="GEO Audit Report — <brand_name>" \
--metadata brand_name="<brand_name>" \
--metadata domain="<domain>" \
--metadata geo_score="<geo_score>" \
--metadata score_label="<score_label>" \
--metadata date="<date>" \
--metadata business_type="<business_type>" \
--metadata locations="<locations>" \
--metadata platform="<platform>" \
-o GEO-REPORT.html
```
### Step 4: Print to PDF with headless Chrome
```bash
"<chrome-binary-path>" \
--headless=new \
--disable-gpu \
--no-sandbox \
--print-to-pdf="$(pwd)/GEO-REPORT.pdf" \
--print-to-pdf-no-header \
--no-pdf-header-footer \
--virtual-time-budget=5000 \
"file://$(pwd)/GEO-REPORT.html"
```
### Step 5: Report completion
Tell the user the PDF path, the file size, and how to open it.
## What the PDF Contains
- **Cover page** — dark navy gradient, brand name, domain, GEO score badge colored by score, audit date, business type, locations, CMS platform
- **Score tables** — cells containing `XX/100` are color-coded: 80 and up green, 65 and up blue, 50 and up amber, 35 and up orange, below 35 red
- **Finding sections** — H3 headings containing "Critical", "High", "Medium", or "Low" get severity-colored left-border callout blocks in red, orange, yellow, or green
- **Section page breaks** — major sections (High Priority, 90-Day Roadmap, Component Score Summary, Generated Schema) start on a new page
- **Code blocks** — JSON schema templates render with dark-theme monospace styling
- **Page footer** — brand name, "GEO Audit", date, and page numbers via CSS `@page`
## Customizing
- **Colors and typography** — edit `geo-pdf/style.css`
- **Cover layout** — edit `geo-pdf/template.html`
- **Score color thresholds** — edit the `scoreColor()` function in the template's `<script>` block
- **Which sections break to a new page** — edit the `breakBefore` array in the template's `<script>` block
## Troubleshooting
| Problem | Fix |
|---|---|
| `pandoc: command not found` | Install pandoc for your OS, then reopen the terminal |
| Chrome not found | Verify the binary path for your OS from the table above |
| PDF is blank or empty | Raise `--virtual-time-budget` to 8000 so the inline script finishes |
| Cover metadata missing | Check that the audit markdown uses the standard header format in Step 2 |
| Fonts not loading | The PDF renders offline and falls back to system fonts. Expected. |
| Score cells not colored | The color-coding runs in the template's inline script. Confirm the cell text matches the `XX/100` pattern. |
What This Does
Takes a finished GEO audit written in markdown and prints it to a styled PDF. Claude reads the cover metadata out of the report header, runs pandoc to build a self-contained HTML file, then drives headless Chrome to print that HTML to PDF.
Pairs with the GEO Client Report Generator, which produces the markdown this consumes.
Quick Start
Step 1: Create a Project Folder
mkdir -p ~/Documents/GEOReports
Step 2: Download the Template
Click Download above, then:
mv ~/Downloads/CLAUDE.md ~/Documents/GEOReports/
Step 3: Start Working
cd ~/Documents/GEOReports
claude
With your audit markdown in the folder, say "turn the audit report into a PDF."
Dependencies
Two external tools, both must be installed before the first run:
- pandoc —
brew install pandoc,winget install JohnMacFarlane.Pandoc, orapt install pandoc - Google Chrome or Chromium — used headless to print the HTML to PDF
The playbook also needs an input file. It looks for GEO-AUDIT-REPORT.md in the current directory and stops if that file is absent rather than inventing audit data.
The upstream geo-seo-claude suite installs a pandoc HTML template and stylesheet under ~/.claude/skills/geo/templates/. Running this as a standalone CLAUDE.md, you will not have them, so the template instructs Claude to generate a local geo-pdf/template.html and geo-pdf/style.css on the first run and reuse them afterward.
What the PDF Contains
- Cover page with a dark navy gradient, brand name, domain, GEO score badge colored by value, audit date, business type, locations, and CMS
- Score cells shaded by threshold: 80 and up green, 65 and up blue, 50 and up amber, 35 and up orange, below 35 red
- Severity callouts on findings, with left borders in red, orange, yellow, or green
- Automatic page breaks before major sections
- Dark-theme monospace styling for JSON schema blocks
- Footer with brand name, date, and page numbers
Troubleshooting
| Problem | Fix |
|---|---|
pandoc: command not found |
Install pandoc, then reopen the terminal |
| Chrome not found | Check the binary path for your OS |
| PDF is blank | Raise --virtual-time-budget to 8000 so the inline script finishes |
| Cover metadata missing | The audit markdown needs the standard header format Claude parses |
| Fonts look wrong | The PDF renders offline and falls back to system fonts. Expected. |