$npx -y skills add zubair-trabzada/geo-seo-claude --skill geo-report-pdfGenerate a professional PDF report from a GEO audit using pandoc + Chrome headless. Converts GEO-AUDIT-REPORT.md into a styled, client-ready PDF with a cover page, color-coded score tables, severity-tagged findings, and a 90-day roadmap.
| 1 | # GEO PDF Report Generator (pandoc pipeline) |
| 2 | |
| 3 | ## Prerequisites |
| 4 | |
| 5 | - **pandoc** — `brew install pandoc` |
| 6 | - **Google Chrome** — must be installed at `/Applications/Google Chrome.app/` |
| 7 | |
| 8 | No Python dependencies. No ReportLab. No JSON data wrangling. |
| 9 | |
| 10 | ## How It Works |
| 11 | |
| 12 | 1. Read `GEO-AUDIT-REPORT.md` in the current directory (created by `/geo audit`) |
| 13 | 2. Extract cover metadata from the report (brand name, domain, GEO score, date, locations) |
| 14 | 3. Run `pandoc` with the bundled CSS + HTML template to produce a self-contained `GEO-REPORT.html` |
| 15 | 4. Run Chrome headless to print the HTML to `GEO-REPORT.pdf` |
| 16 | |
| 17 | The pandoc template (`~/.claude/skills/geo/templates/geo-report-template.html`) injects: |
| 18 | - A full-bleed dark navy cover section with the GEO score badge |
| 19 | - Per-section cover metadata (date, business type, locations, platform) |
| 20 | - JavaScript that runs inside Chrome before printing to color-code score cells and severity-tag finding sections |
| 21 | |
| 22 | ## Workflow |
| 23 | |
| 24 | ### Step 1: Check for audit report |
| 25 | |
| 26 | Look for `GEO-AUDIT-REPORT.md` in the current directory. If absent, tell the user to run `/geo audit <url>` first. |
| 27 | |
| 28 | ### Step 2: Extract cover metadata from the report |
| 29 | |
| 30 | Read the top of `GEO-AUDIT-REPORT.md` and extract: |
| 31 | |
| 32 | | Field | Where to find it | |
| 33 | |---|---| |
| 34 | | `brand_name` | First H1 title (after "GEO Audit Report:") | |
| 35 | | `domain` | Second bold line (e.g. `**Domain:** alexamediasolutions.com`) | |
| 36 | | `geo_score` | Line matching `## Overall GEO Score: XX / 100` | |
| 37 | | `score_label` | Word after the score on that same line (e.g. "Poor", "Fair", "Good") | |
| 38 | | `date` | `**Audit Date:**` line | |
| 39 | | `business_type` | `**Business Type:**` line | |
| 40 | | `locations` | `**Locations:**` line | |
| 41 | | `platform` | `**CMS:**` line | |
| 42 | |
| 43 | ### Step 3: Run pandoc |
| 44 | |
| 45 | ```bash |
| 46 | pandoc GEO-AUDIT-REPORT.md \ |
| 47 | --to html5 \ |
| 48 | --standalone \ |
| 49 | --embed-resources \ |
| 50 | --template ~/.claude/skills/geo/templates/geo-report-template.html \ |
| 51 | --css ~/.claude/skills/geo/templates/geo-report-style.css \ |
| 52 | --metadata title="GEO Audit Report — <brand_name>" \ |
| 53 | --metadata brand_name="<brand_name>" \ |
| 54 | --metadata domain="<domain>" \ |
| 55 | --metadata geo_score="<geo_score>" \ |
| 56 | --metadata score_label="<score_label>" \ |
| 57 | --metadata date="<date>" \ |
| 58 | --metadata business_type="<business_type>" \ |
| 59 | --metadata locations="<locations>" \ |
| 60 | --metadata platform="<platform>" \ |
| 61 | -o GEO-REPORT.html |
| 62 | ``` |
| 63 | |
| 64 | Replace `<field>` placeholders with values extracted in Step 2. If a field is not found in the report, omit that `--metadata` flag — the template has sensible defaults. |
| 65 | |
| 66 | ### Step 4: Run Chrome headless |
| 67 | |
| 68 | ```bash |
| 69 | "/Applications/Google Chrome.app/Contents/MacOS/Google Chrome" \ |
| 70 | --headless=new \ |
| 71 | --disable-gpu \ |
| 72 | --no-sandbox \ |
| 73 | --print-to-pdf="$(pwd)/GEO-REPORT.pdf" \ |
| 74 | --print-to-pdf-no-header \ |
| 75 | --no-pdf-header-footer \ |
| 76 | --virtual-time-budget=5000 \ |
| 77 | "file://$(pwd)/GEO-REPORT.html" |
| 78 | ``` |
| 79 | |
| 80 | ### Step 5: Report completion |
| 81 | |
| 82 | Tell the user: |
| 83 | - `GEO-REPORT.pdf` was generated in the current directory |
| 84 | - File size |
| 85 | - Optionally: `open GEO-REPORT.pdf` to preview it |
| 86 | |
| 87 | ## What the PDF Contains |
| 88 | |
| 89 | - **Cover page** — Dark navy gradient, brand name, domain, GEO score badge (colored by score), audit date, business type, locations, CMS platform |
| 90 | - **Score tables** — Cells containing `XX/100` are color-coded: ≥80 green, ≥65 blue, ≥50 amber, ≥35 orange, <35 red |
| 91 | - **Finding sections** — `h3` headings containing "Critical / High / Medium / Low" get severity-colored left-border callout blocks (red / orange / yellow / green) |
| 92 | - **Section page breaks** — Major sections (High Priority, 90-Day Roadmap, Component Score Summary, Generated Schema) break to new pages automatically |
| 93 | - **Code blocks** — JSON schema templates render with dark theme monospace styling |
| 94 | - **Page footer** — Brand name · GEO Audit · date + page numbers (via CSS `@page`) |
| 95 | |
| 96 | ## Customizing the Report |
| 97 | |
| 98 | - **Colors / typography** — Edit `~/.claude/skills/geo/templates/geo-report-style.css` |
| 99 | - **Cover layout** — Edit `~/.claude/skills/geo/templates/geo-report-template.html` |
| 100 | - **Score thresholds for color-coding** — Edit the `scoreColor()` function in the template's `<script>` block |
| 101 | - **Which sections get page breaks** — Edit the `breakBefore` array in the template's `<script>` block |
| 102 | |
| 103 | ## Troubleshooting |
| 104 | |
| 105 | | Problem | Fix | |
| 106 | |---|---| |
| 107 | | `pandoc: command not found` | `brew install pandoc` | |
| 108 | | Chrome not found | Check path: `/Applications/Google Chrome.app/Contents/MacOS/Google Chrome` | |
| 109 | | PDF is blank / empty | Increase `--virtual-time-budget` to 8000 | |
| 110 | | Cover metadata missing | Check GEO-AUDIT-REPORT.md has the standard header format | |
| 111 | | Fonts not loading | PDF is rendered offline; |