
Growth Report
- 76 installs
- 93 repo stars
- Updated June 28, 2026
- infrasity-labs/dev-gtm-claude-skills
Growth Report is an agent skill that compiles a 3-month SEO performance HTML report from live DataForSEO data for your domain and competitors.
About
Growth Report is an agent skill for SEO and growth teams who need a polished quarterly briefing without stitching spreadsheets manually. You supply a primary domain and competitor domains; the workflow calls DataForSEO for baseline versus current traffic, keyword ranking distributions, top content pages, and trend lines across the competitive set, then renders a shareable HTML report with an executive summary and strategic priorities. It targets agencies, in-house SEO leads, and developer-marketing teams tracking competitive search positioning after launch. Use it when leadership or clients expect numbers-backed narrative on what moved in organic search over roughly three months. The output is a single HTML file suitable for email or slide decks, with dark-theme styling aimed at executive readers. It assumes you have DataForSEO access configured in the dev-gtm Claude skills environment and that competitor lists are intentional, not guessed.
- Builds a dark-theme executive HTML report for a target domain plus named competitors
- Pulls baseline vs current traffic, keyword ranking buckets, top pages, and historical trends via DataForSEO
- States that every metric comes from live API responses—no placeholders or estimates
- Covers traffic trends, content clusters, competitive positioning, and strategic priorities in one artifact
- Triggered from the dev-gtm skill repo with `/dev-gtm growth-report <domain> <competitors...>`
Growth Report by the numbers
- 76 all-time installs (skills.sh)
- +4 installs in the week ending Jul 25, 2026 (Skillselion tracking)
- Ranked #1,198 of 1,881 Marketing & SEO skills by installs in the Skillselion catalog
- Data as of Jul 26, 2026 (Skillselion catalog sync)
npx skills add https://github.com/infrasity-labs/dev-gtm-claude-skills --skill growth-reportAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 76 |
|---|---|
| repo stars | ★ 93 |
| Last updated | June 28, 2026 |
| Repository | infrasity-labs/dev-gtm-claude-skills ↗ |
What it does
Produce a client- or leadership-ready 3-month SEO performance HTML report from live DataForSEO traffic, rankings, and competitor data for one domain.
Who is it for?
Best when you're shipping quarterly SEO reviews for one primary domain with a defined competitor set and DataForSEO already wired up.
Skip if: Skip if you're without DataForSEO credentials, one-off keyword research before launch, or anyone and only needs a lightweight traffic snapshot without competitor history.
When should I use this skill?
User asks for a growth or SEO performance report for a domain and competitors via `/dev-gtm growth-report` or equivalent dev-gtm trigger.
What you get
You get an executive-ready HTML report with verified API-backed traffic, rankings, content clusters, and competitor trends you can share as-is.
- Dark-theme executive HTML SEO growth report
By the numbers
- 3-month SEO performance HTML report
- Live DataForSEO API data with no placeholder metrics
Files
SEO Performance Report Skill
Generates a comprehensive 3-month SEO performance HTML report using live DataForSEO data. The report covers traffic trends, keyword rankings, top content clusters, competitive positioning, strategic priorities, and an executive summary — all in the Infrasity brand design system.
---
STEP 0 — COLLECT ALL INPUTS BEFORE DOING ANYTHING
All four inputs are mandatory. Do not make any API calls until all four are confirmed.
Collect them in a single message using this exact format — ask for everything at once, never ask for inputs one at a time:
---
If the user has NOT provided all four inputs, ask:
To generate the report I need 4 things:
>
1. Target domain — the site to report on, e.g. firefly.ai2. Competitor domains — up to 5–6 competitors, e.g. spacelift.io, env0.com, terraform.io3. Date range — start and end date for the 3-month window (default: Feb 20 → May 20, 2026)
4. Location — country for search data (default: United States)
>
Which of these do you want to change from the defaults?
---
If the user has already provided the target domain and competitors (e.g. "generate SEO report for firefly.ai vs spacelift.io, env0.com"), confirm the two optional inputs:
Got it — I'll generate the report for firefly.ai vs spacelift.io, env0.com.
>
Just confirming the defaults:
- Date range: Feb 20 → May 20, 2026
- Location: United States
>
OK to proceed with these, or would you like to change either?
---
Input parsing rules:
| Input | Rules |
|---|---|
TARGET_DOMAIN | Strip https://, http://, www., and trailing slashes. Store bare domain only (e.g. firefly.ai) |
COMPETITORS | Strip same prefixes from each. Accept comma-separated or space-separated list. Min 2, max 6 competitors. |
START_DATE | Parse any human date format → YYYY-MM-DD. Default: 2026-02-20 |
END_DATE | Parse any human date format → YYYY-MM-DD. Default: 2026-05-20 |
LOCATION | Accept country name. Default: United States. Must be a valid DataForSEO location_name (full country name only, never city or region). |
After confirmation, echo back the resolved inputs clearly before proceeding:
✓ Target: firefly.ai
✓ Competitors: spacelift.io, env0.com, controlmonkey.io, scalr.com, terraform.io
✓ Date range: Feb 20, 2026 → May 20, 2026
✓ Location: United States
>
Fetching data now...
---
CRITICAL API SETTINGS
Always use `ignore_synonyms: false` on every DataForSEO call. Using the default ignore_synonyms: true underreports traffic and keyword counts by 30–50%. This is the single most important parameter to get right — never omit it.
---
STEP 1 — Baseline Metrics
Call dataforseo_labs_google_historical_rank_overview with:
target: TARGET_DOMAIN
location_name: LOCATION
language_code: en
ignore_synonyms: falseFrom the returned monthly array, find the snapshot closest to START_DATE (match by year+month). Extract and store:
baseline_traffic=metrics.organic.etvbaseline_keywords=metrics.organic.countbaseline_top3=metrics.organic.pos_1+metrics.organic.pos_2_3
⚠️ There is NOpos_1_3field in DataForSEO. Always compute Top 3 aspos_1 + pos_2_3.
Also extract all monthly snapshots between START_DATE and END_DATE for the traffic trend bars in the report (typically 3–4 data points):
- For each snapshot store:
month_label(e.g. "Feb 2026"),etv,year,month - Sort ascending by date
- These become
TREND_LABEL_1..4,TREND_ETV_1..4in the HTML template
---
STEP 2 — Current Metrics
Call dataforseo_labs_google_domain_rank_overview with:
target: TARGET_DOMAIN
location_name: LOCATION
language_code: en
ignore_synonyms: falseExtract from metrics.organic:
current_traffic=etvcurrent_keywords=countcurrent_top3=pos_1+pos_2_3current_pos_1=pos_1current_pos_2_3=pos_2_3current_pos_4_10=pos_4_10current_pos_11_20=pos_11_20current_pos_21_100= sum ofpos_21_30+pos_31_40+pos_41_50+pos_51_60+pos_61_70+pos_71_80+pos_81_90+pos_91_100
Calculate all deltas:
traffic_growth_pct = ((current_traffic - baseline_traffic) / baseline_traffic) * 100
keywords_change = current_keywords - baseline_keywords
keywords_change_pct = (keywords_change / baseline_keywords) * 100
top3_growth_pct = ((current_top3 - baseline_top3) / baseline_top3) * 100Format rules:
- Prefix
+for positive values,-is automatic for negative - Round all percentages to 1 decimal place
- Add
posCSS class for positive deltas,negfor negative
---
STEP 3 — Competitive Landscape
3a — Current Traffic Snapshot
Call dataforseo_labs_bulk_traffic_estimation with:
targets: [TARGET_DOMAIN, ...COMPETITORS] ← all domains in a single API call
location_name: LOCATION
language_code: en
item_types: ["organic"]
ignore_synonyms: falseFor each domain returned, extract: etv, count.
Sort all domains descending by etv. Assign rank 1 = highest traffic. Determine:
competitive_rank= rank position of TARGET_DOMAIN (1 = #1)total_domains= total count of all domains in the tabledomain_above= domain ranked one position above TARGET_DOMAIN (if any)domain_below= domain ranked one position below TARGET_DOMAIN (if any)gap_to_next_above= etv of domain_above − current_traffic (0 if TARGET_DOMAIN is #1)lead_over_next_below= current_traffic − etv of domain_below (0 if TARGET_DOMAIN is last)
3b — Competitor Trend Signals (Historical, Option 1)
For each competitor (not the target domain), call dataforseo_labs_google_historical_rank_overview:
target: COMPETITOR_DOMAIN
location_name: LOCATION
language_code: en
ignore_synonyms: falseFrom the returned monthly array:
- Find the snapshot closest to START_DATE → extract
comp_baseline_etv - Find the snapshot closest to END_DATE → extract
comp_current_etv - Calculate:
comp_trend_pct = ((comp_current_etv - comp_baseline_etv) / comp_baseline_etv) * 100
Trend badge assignment rules (±5% stability threshold):
| Condition | Badge | CSS class |
|---|---|---|
comp_trend_pct > +5% | ↑ +X.X% | trend-up (green) |
comp_trend_pct < -5% | ↓ -X.X% | trend-down (red) |
-5% ≤ comp_trend_pct ≤ +5% | → Stable (X.X%) | trend-stable (gray) |
TARGET_DOMAIN trend for the competitive table must also use the same START_DATE → END_DATE window for consistency. The historical data fetched in Step 1 already contains this:
target_table_trend_pct = ((end_date_snapshot_etv - baseline_traffic) / baseline_traffic) * 100
Where end_date_snapshot_etv is the ETV from the Step 1 historical array snapshot closest to END_DATE (not current_traffic from Step 2, which is a live figure).
Apply the same ±5% threshold rules to derive the target's trend badge.
⚠️ traffic_growth_pct from Step 2 (baseline → live) is used for the timeline cards,delta badges, and executive summary — but NOT for the competitive table trend column.
The competitive table trend column uses target_table_trend_pct (START_DATE → END_DATE)for all domains including the target, ensuring a consistent apples-to-apples comparison.
⚠️ Never default any competitor to "Stable" without running this calculation.
Every trend badge in the competitive table must be derived from real historical ETV data.
---
STEP 4 — Top Content Clusters
Call dataforseo_labs_google_relevant_pages with:
target: TARGET_DOMAIN
location_name: LOCATION
language_code: en
order_by: ["metrics.organic.etv,desc"]
limit: 3
ignore_synonyms: falseFor each of the top 3 pages extract:
page_address— shorten display URL: removehttps://www.prefix, keep pathmetrics.organic.etv→ page_etv (format with commas, round to nearest integer)metrics.organic.count→ page_keywords
Homepage concentration check: If page_1_etv / current_traffic > 0.80, set homepage_concentration = true. This triggers a specific paragraph in the executive summary.
---
STEP 5 — Derive Report Targets (Q2 Card)
IF traffic_growth_pct >= 0:
traffic_goal = round(current_traffic * (1 + traffic_growth_pct/100))
ELSE:
traffic_goal = round(baseline_traffic * 0.9) ← recovery target
keywords_goal = max(round(current_keywords * 1.2), round(baseline_keywords * 0.95))
top3_goal = round(current_top3 * 1.3)
IF competitive_rank == 1:
target_badge = "Maintain #1"
ELSE:
target_badge = "Challenge #" + str(competitive_rank - 1)Format traffic_goal as e.g. 62,000+. Round to nearest thousand for clean presentation.
---
STEP 6 — Derive Strategic Priority Cards
Always generate exactly 6 cards. Use actual data values in every description — no generic text. Reference competitor trend data from Step 3b to enrich card descriptions where relevant.
| # | Card title formula | Content rule |
|---|---|---|
| 1 | "Close Gap to #[rank_above]" | Name domain_above, state gap_to_next_above as ETV and its trend badge (growing/declining). If declining, frame as narrowing window opportunity. |
| 2 | "Defend vs. / Watch [domain_below or fastest_growing_competitor]" | If a lower-ranked competitor is growing fast (>+20%), flag it as a rising threat. Otherwise name domain_below, state lead_over_next_below. |
| 3 | Traffic recovery OR scale | If declined: "Reverse the [X]% Decline" with pos_4_10 count as pipeline. If grew: "Sustain [X]% Growth Trajectory" and note market context (e.g. if most competitors declined) |
| 4 | "Scale Top Content Clusters" | Reference page_1 URL and its ETV; flag homepage concentration if true |
| 5 | "Recover/Expand Keyword Coverage" | Use keywords_change as the specific number to recover or build on |
| 6 | "Convert Pos 4–10 to Top 3" | Use current_pos_4_10 count; state that converting 20% would add ~N new top-3 rankings |
---
STEP 7 — Derive Executive Summary (4 paragraphs)
Write naturally — no bullet points inside the paragraphs. All numbers must be real API values.
- Para 1: Overall result. State traffic_growth_pct, competitive_rank of total_domains. State the trend distribution of competitors (how many are growing, stable, or declining derived from Step 3b) and whether the target is the fastest growing. Name the domains ranked immediately above and below with their ETVs and trend directions.
- Para 2: If
homepage_concentration = true: flag that X% of traffic comes from one page,
frame it as both a risk and an opportunity to diversify. Otherwise: describe content breadth advantage — keyword count vs competitors.
- Para 3: Top 3 keywords trend (top3_growth_pct). Flag keywords_change — if negative,
state the specific number lost and the urgency to recapture. If positive, call it momentum.
- Para 4: Q2 strategy. Name the specific gap to close (gap_to_next_above), the competitor
to chase (domain_above) and whether it is growing or declining. If domain_above is declining, frame the opportunity as a narrowing window. Name the recovery/scale action most impactful based on the data.
Fastest growing determination — compare target_table_trend_pct against all competitors' comp_trend_pct values from Step 3b. If TARGET_DOMAIN has the highest trend percentage in the set, set is_fastest_growing = true. Use this in Para 1 and the summary badge.
Summary badge format: Rank #[competitive_rank] | [current_traffic_K]K Traffic | [traffic_growth_pct]% Growth | [current_top3] Top-3 Keywords | [Fastest Growing / Declining / Stable]
Where the last label is:
- Fastest Growing if is_fastest_growing = true
- Growing if traffic_growth_pct > 5% and not fastest growing
- Declining if traffic_growth_pct < -5% and not fastest growing
- Stable if -5% <= traffic_growth_pct <= +5% and not fastest growing
---
STEP 8 — Generate the HTML Report
Read references/html-template.md for the complete HTML structure, CSS, and variable map.
The template uses the Infrasity brand design system exclusively:
- Background:
#0D0A1A(Blackish-Violet) — never white, never any other dark - Primary accent:
#8157F2— the only accent colour; never substitute blue or green - Fonts:
Instrument Sansfor all headings / KPI values / section numbers,
DM Sans for all body / labels / UI text, DM Mono for paths / code / data values
- Status colours:
#5DCEA6(positive delta),#F07070(negative delta)
Do not alter, override, or mix in any other colour palette or font stack. Fill every {{VARIABLE}} with real data. Output the file to:
/mnt/user-data/outputs/{TARGET_DOMAIN}_seo_report.htmlThen call present_files to deliver it to the user.
---
ERROR HANDLING
| Situation | Action |
|---|---|
| Domain returns no data from bulk_traffic_estimation | Omit that domain from the competitive table; add a footnote |
| Historical snapshot missing for START_DATE or END_DATE month | Use nearest available month; note actual date used in report footer |
baseline_traffic is 0 (division by zero) | Set traffic_growth_pct to "N/A", skip all delta badges that depend on it, and note in the report footer that baseline data was unavailable for START_DATE |
baseline_top3 is 0 (division by zero) | Set top3_growth_pct to "N/A" and skip the delta badge |
comp_baseline_etv is 0 (division by zero for competitor trend) | Mark that competitor as "N/A" in the trend column |
backlinks_bulk_ranks 40204 error | Do not call this endpoint — it requires a separate subscription. Skip entirely. |
ai_opt_llm_ment_agg_metrics 40204 error | Do not include AI citations section. It is excluded from this skill. |
---
WHAT NOT TO INCLUDE
- ❌ No AI/LLM citation section — excluded by design (requires paid DataForSEO add-on)
- ❌ No DFS Rank (0–1000) column — excluded by design (requires separate subscription)
- ❌ No `ignore_synonyms: true` — always
false, no exceptions - ❌ No placeholder text — every number in the HTML must come from a real API response
- ❌ No asking for inputs one at a time — always collect all missing inputs in a single message
- ❌ No defaulting competitors to "Stable" — always derive trend from historical ETV comparison
---
REFERENCE FILES
references/html-template.md— Full Infrasity-branded HTML template with CSS design system,
all section markup, competitive table row patterns, and complete variable substitution map. Always read this file before writing any HTML. The Infrasity design is the only permitted output design — do not use any other colour palette, font stack, or layout.
Growth Report
Generates a comprehensive 3-month SEO performance HTML report for any domain using live DataForSEO data. Covers traffic trends, keyword rankings, top content clusters, competitive positioning, strategic priorities, and an executive summary — delivered as a dark-theme executive-ready HTML file.
---
What this skill does
You provide a target domain and a list of competitors. The skill pulls live data from DataForSEO — baseline vs current traffic, keyword ranking distributions, top content pages, and historical trend data for every competitor — then compiles it into a polished HTML report you can share directly with leadership or clients.
Every number in the report comes from a real API response. No placeholder text, no estimates.
Built for:
- SEO teams delivering monthly or quarterly performance briefings
- Agencies producing client-facing SEO reports at scale
- Developer marketing and growth teams tracking competitive SEO positioning
---
Installation
Claude Code (Recommended)
Clone the repo — the skill activates automatically when you open it in Claude Code:
git clone https://github.com/Infrasity-Labs/dev-gtm-claude-skills.git
cd dev-gtm-claude-skills
claudeThen trigger it with:
/dev-gtm growth-report firefly.ai spacelift.io env0.com terraform.ioClaude Web (Free / Pro)
1. Go to [Settings → Capabilities](https://claude.ai/settings/capabilities) and enable Code execution and file creation 2. Go to [Customize → Skills](https://claude.ai/customize/skills) 3. Click + → Create skill → Upload a skill 4. Zip this skill folder and upload it:
cd dev-gtm-claude-skills/skills
zip -r growth-report.zip growth-report/Upload growth-report.zip and toggle it on.
---
DataForSEO Setup (Required)
This skill requires a DataForSEO account. All traffic, keyword, and competitive data is fetched live from their API.
Claude Code
Open .claude/settings.json in the cloned repo and replace the placeholder credentials:
{
"mcpServers": {
"dataforseo": {
"command": "npx",
"args": ["-y", "@dataforseo/mcp-server"],
"env": {
"DATAFORSEO_USERNAME": "your-dataforseo-username",
"DATAFORSEO_PASSWORD": "your-dataforseo-password"
}
}
}
}Claude Web (Free / Pro)
Go to [Settings → Integrations](https://claude.ai/settings/integrations), find DataForSEO, and connect your account with your API credentials.
---
How to use
Generate SEO report for firefly.ai vs spacelift.io, env0.com, terraform.io/dev-gtm growth-report stripe.com braintree.com adyen.comThe skill asks for any missing inputs in a single message — target domain, competitors (up to 6), date range, and location. It comes with sensible defaults so you can confirm and proceed immediately.
Inputs
| Input | Required | Default |
|---|---|---|
| Target domain | ✅ | — |
| Competitor domains | ✅ Min 2, max 6 | — |
| Date range | ⬜ | Last 3 months |
| Location | ⬜ | United States |
---
What the report covers
Timeline cards — traffic, keyword count, and top-3 ranking changes over the date range with delta badges (percentage growth or decline vs baseline).
Traffic trend bars — monthly ETV snapshots across the date window, showing the trajectory visually.
Competitive landscape table — all domains ranked by current traffic with each competitor's trend badge (growing / stable / declining) derived from real historical data.
Top content clusters — the 3 highest-traffic pages on the target domain with their ETV and keyword counts.
Q2 targets card — automatically derived traffic, keyword, and top-3 goals based on the current trajectory.
6 strategic priority cards — data-driven actions: gap to next competitor, threats from rising competitors, traffic recovery or scale path, content cluster opportunities, keyword coverage recovery, and top-10-to-top-3 conversion.
Executive summary — 4 paragraphs written from the data: overall result, content concentration analysis, keyword trend, and Q2 strategy. All numbers are real API values.
---
Output
An HTML file saved to /mnt/user-data/outputs/<domain>_seo_report.html, delivered via present_files.
The report is fully self-contained — no external dependencies, no CDN links. Open it in a browser or attach it directly to a Slack message or email.
---
File structure
growth-report/
├── SKILL.md # Skill instructions Claude follows
├── README.md # This file
└── references/
└── html-template.md # Full HTML/CSS report template with variable mapHTML Report Template Reference — Infrasity Brand Design
This file contains the complete Infrasity-branded HTML template for the SEO Performance Report. Replace all {{VARIABLE}} placeholders with real data from the DataForSEO API calls.
Design system: Infrasity brand v1 — #0D0A1A background · #8157F2 purple accent · Instrument Sans + DM Sans + DM Mono. No other colour palette or font stack is permitted.
---
Variable Reference
| Variable | Source |
|---|---|
{{TARGET_DOMAIN}} | User input |
{{START_DATE}} | User input (e.g. Feb 20, 2026) |
{{END_DATE}} | User input (e.g. May 20, 2026) |
{{BASELINE_TRAFFIC}} | Step 1: historical etv, formatted with commas |
{{BASELINE_KEYWORDS}} | Step 1: historical count, formatted with commas |
{{BASELINE_TOP3}} | Step 1: pos_1 + pos_2_3, formatted with commas |
{{BASELINE_RANK}} | Step 3: competitive rank at baseline period |
{{CURRENT_TRAFFIC}} | Step 2: current etv, formatted with commas |
{{CURRENT_KEYWORDS}} | Step 2: current count, formatted with commas |
{{CURRENT_TOP3}} | Step 2: pos_1 + pos_2_3 |
{{CURRENT_COMP_RANK}} | Step 3: rank in sorted competitive table |
{{TOTAL_COMPETITORS}} | Count of all domains including target |
{{TRAFFIC_GROWTH_PCT}} | Step 2 calc: formatted like "+36.2%" or "-31.4%" |
{{TRAFFIC_GROWTH_CLASS}} | "pos" if positive, "neg" if negative |
{{KEYWORDS_CHANGE}} | Step 2 calc: e.g. "-1,147" or "+523" |
{{KEYWORDS_CHANGE_PCT}} | Step 2 calc: e.g. "-50.1%" |
{{KEYWORDS_CHANGE_CLASS}} | "pos" or "neg" |
{{TOP3_GROWTH_PCT}} | Step 2 calc: e.g. "+28.9%" |
{{TOP3_GROWTH_CLASS}} | "pos" or "neg" |
{{TARGET_GOAL_TRAFFIC}} | Step 5 derived target |
{{TARGET_GOAL_KEYWORDS}} | Step 5 derived target |
{{TARGET_GOAL_TOP3}} | Step 5 derived target |
{{TARGET_BADGE_TEXT}} | e.g. "Challenge #2" or "Maintain #1" |
{{COMP_TABLE_ROWS}} | Step 3: HTML <tr> rows for all domains |
{{MARKET_INSIGHT_TEXT}} | Step 3: 2–3 sentence market insight paragraph |
{{BIG_STAT_VAL}} | e.g. "+36.2%" — the hero traffic growth number |
{{BIG_STAT_CLASS}} | "green" if positive, "red" if negative |
{{GAP_TO_NEXT}} | Step 3: etv gap to competitor one rank above |
{{NEXT_ABOVE_DOMAIN}} | Domain ranked one above target |
{{LEAD_BELOW_DOMAIN}} | Domain ranked one below target |
{{LEAD_OVER_BELOW}} | etv lead over competitor one rank below |
{{TREND_LABEL_1}} | Month label for trend bar 1 (e.g. "Feb 2026") |
{{TREND_ETV_1}} | ETV value for trend bar 1 |
{{TREND_BAR_WIDTH_1}} | Width % for trend bar 1 (highest month = 100%) |
{{TREND_LABEL_2}} | Month label for trend bar 2 |
{{TREND_ETV_2}} | ETV value for trend bar 2 |
{{TREND_BAR_WIDTH_2}} | Width % for trend bar 2 |
{{TREND_LABEL_3}} | Month label for trend bar 3 |
{{TREND_ETV_3}} | ETV value for trend bar 3 |
{{TREND_BAR_WIDTH_3}} | Width % for trend bar 3 |
{{TREND_LABEL_4}} | Month label for trend bar 4 |
{{TREND_ETV_4}} | ETV value for trend bar 4 |
{{TREND_BAR_WIDTH_4}} | Width % for trend bar 4 |
{{KW_POS_1}} | Step 2: pos_1 count |
{{KW_POS_2_3}} | Step 2: pos_2_3 count |
{{KW_POS_4_10}} | Step 2: pos_4_10 count |
{{KW_POS_11_20}} | Step 2: pos_11_20 count |
{{KW_POS_21_100}} | Step 2: sum pos_21_30 through pos_91_100 |
{{PAGE1_URL}} | Step 4: top page address (strip https://www.) |
{{PAGE1_ETV}} | Step 4: top page etv |
{{PAGE1_KW}} | Step 4: top page keyword count |
{{PAGE2_URL}} | Step 4: second page address |
{{PAGE2_ETV}} | Step 4: second page etv |
{{PAGE2_KW}} | Step 4: second page keyword count |
{{PAGE3_URL}} | Step 4: third page address |
{{PAGE3_ETV}} | Step 4: third page etv |
{{PAGE3_KW}} | Step 4: third page keyword count |
{{STRAT_1_NUM_LABEL}} | Label for strategy card 1 (e.g. "Close Gap") |
{{STRAT_1_TITLE}} | Strategic priority 1 title |
{{STRAT_1_DESC}} | Strategic priority 1 description |
{{STRAT_2_NUM_LABEL}} | Label for strategy card 2 |
{{STRAT_2_TITLE}} | Strategic priority 2 title |
{{STRAT_2_DESC}} | Strategic priority 2 description |
{{STRAT_3_NUM_LABEL}} | Label for strategy card 3 |
{{STRAT_3_TITLE}} | Strategic priority 3 title |
{{STRAT_3_DESC}} | Strategic priority 3 description |
{{STRAT_4_NUM_LABEL}} | Label for strategy card 4 |
{{STRAT_4_TITLE}} | Strategic priority 4 title |
{{STRAT_4_DESC}} | Strategic priority 4 description |
{{STRAT_5_NUM_LABEL}} | Label for strategy card 5 |
{{STRAT_5_TITLE}} | Strategic priority 5 title |
{{STRAT_5_DESC}} | Strategic priority 5 description |
{{STRAT_6_NUM_LABEL}} | Label for strategy card 6 |
{{STRAT_6_TITLE}} | Strategic priority 6 title |
{{STRAT_6_DESC}} | Strategic priority 6 description |
{{EXEC_PARA_1}} | Executive summary paragraph 1 |
{{EXEC_PARA_2}} | Executive summary paragraph 2 |
{{EXEC_PARA_3}} | Executive summary paragraph 3 |
{{EXEC_PARA_4}} | Executive summary paragraph 4 |
{{EXEC_BADGE_TEXT}} | Summary badge text |
{{COMP_TABLE_LABEL}} | "X of Y" competitive position label |
{{FASTEST_GROWING_COLOR}} | CSS colour for fastest growing label (var(--up) or var(--text-3)) |
{{FASTEST_GROWING_LABEL}} | Text label for the fastest growing domain |
{{RANK_ABOVE}} | Rank number of the competitor immediately above |
{{COMP_DOMAIN_LIST}} | Comma-separated list of all domains in the set |
---
Trend Bar Width Calculation
max_etv = highest ETV value across the 4 monthly data points
width_pct_N = round((etv_N / max_etv) * 100)Minimum width = 10% so labels are always visible.
---
Competitive Table Row Template
CSS classes used in the table rows — match exactly:
<!-- Target domain row (highlighted): -->
<tr class="hl">
<td><span class="rank-badge rank-N">N</span></td>
<td><span class="dname me">🔥 {{TARGET_DOMAIN}}</span></td>
<td><span class="mono">{{ETV_FORMATTED}}</span></td>
<td><span class="mono">{{KW_COUNT_FORMATTED}}</span></td>
<td><span class="tbadge t-up">↑ +XX%</span></td>
</tr>
<!-- Competitor row: -->
<tr>
<td><span class="rank-badge rank-N">N</span></td>
<td><span class="dname">{{DOMAIN}}</span></td>
<td><span class="mono">{{ETV_FORMATTED}}</span></td>
<td><span class="mono">{{KW_COUNT_FORMATTED}}</span></td>
<td><span class="tbadge t-stable">→ Stable</span></td>
</tr>Rank badge classes: rank-1 (red), rank-2 (gold), rank-3 (purple), rank-other (gray). Trend badge classes: t-up (green #5DCEA6), t-dn (red #F07070), t-stable (muted gray).
---
Infrasity Design Pre-fill Checklist
Before writing the HTML, confirm every item:
- [ ] Background is
#0D0A1A— not black, not navy, not any other dark - [ ] Primary accent is
#8157F2only — never blue, teal, or any other colour - [ ]
Instrument Sanson all headings, KPI values, section numbers, badges - [ ]
DM Sanson all body copy, table cells, descriptions, labels - [ ]
DM Monoon all URL paths, ETV values in bars, footer data note - [ ] All cards use
border-radius: 12pxandvar(--surface)background - [ ] Purple
rgba(129,87,242,0.35)border appears on card hover - [ ] Status chips:
#5DCEA6(up/positive),#F07070(down/negative) - [ ] Trend bars use
rgba(129,87,242,0.75)fill; target domain bar uses#8157F2 - [ ] Table header:
rgba(129,87,242,0.06)background ·rgba(129,87,242,0.80)text - [ ] No light-mode styles — this is a dark-only output
- [ ] Google Fonts loaded: Instrument Sans + DM Sans + DM Mono
---
Full HTML Template
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>{{TARGET_DOMAIN}} — SEO Performance Report</title>
<link href="https://fonts.googleapis.com/css2?family=Instrument+Sans:wght@400;500;600;700&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;1,9..40,300&family=DM+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
html{scroll-behavior:smooth}
:root{
--bg:#0D0A1A;
--purple:#8157F2;
--purple-deep:#6B3FD4;
--purple-light:#EFE0FF;
--surface:rgba(255,255,255,0.04);
--surface-2:rgba(255,255,255,0.07);
--surface-3:rgba(255,255,255,0.10);
--border:rgba(255,255,255,0.08);
--border-2:rgba(255,255,255,0.15);
--border-purple:rgba(129,87,242,0.35);
--text-1:#FFFFFF;
--text-2:rgba(255,255,255,0.60);
--text-3:rgba(255,255,255,0.30);
--up:#5DCEA6;
--up-bg:rgba(93,206,166,0.10);
--dn:#F07070;
--dn-bg:rgba(240,112,112,0.10);
--head:'Instrument Sans',sans-serif;
--body:'DM Sans',sans-serif;
--mono:'DM Mono',monospace;
}
body{font-family:var(--body);background:var(--bg);color:var(--text-1);font-size:14px;line-height:1.5;-webkit-font-smoothing:antialiased}
.page{max-width:940px;margin:0 auto;padding:48px 28px 88px}
/* ── HEADER ─────────────────────────────────────── */
.hdr{text-align:center;padding:44px 0 40px}
.hdr-pill{display:inline-flex;align-items:center;gap:8px;background:rgba(129,87,242,0.08);border:1px solid rgba(129,87,242,0.22);border-radius:100px;padding:5px 16px;font-family:var(--head);font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--purple-light);margin-bottom:22px}
.hdr-pill-dot{width:6px;height:6px;border-radius:50%;background:var(--purple);box-shadow:0 0 8px var(--purple);flex-shrink:0}
.hdr-title{font-family:var(--head);font-size:clamp(30px,4.5vw,46px);font-weight:700;line-height:1.12;margin-bottom:8px;letter-spacing:-.01em}
.hdr-title em{font-style:normal;color:var(--purple)}
.hdr-sub{color:var(--text-3);font-size:12px;font-family:var(--mono);letter-spacing:.02em}
.hdr-divider{width:64px;height:1px;background:rgba(129,87,242,0.30);margin:18px auto 0}
/* ── SECTION HEADER ─────────────────────────────── */
.sec-hdr{display:flex;align-items:center;gap:10px;margin:48px 0 18px}
.sec-dot{width:5px;height:5px;border-radius:50%;background:var(--purple);box-shadow:0 0 7px var(--purple);flex-shrink:0}
.sec-num{font-family:var(--head);font-size:10px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--purple)}
.sec-label{font-family:var(--head);font-size:19px;font-weight:600;color:var(--text-1)}
/* ── TIMELINE ───────────────────────────────────── */
.timeline{display:grid;grid-template-columns:repeat(3,1fr);gap:14px;margin-bottom:48px;position:relative}
.timeline::before{content:'';position:absolute;top:44px;left:calc(33.33% - 4px);width:calc(33.33% + 8px);height:1px;background:rgba(129,87,242,0.25);z-index:0}
.tc{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:22px 20px;position:relative;z-index:1;transition:border-color .2s}
.tc:hover{border-color:var(--border-purple)}
.tc.live{background:rgba(129,87,242,0.07);border-color:var(--border-purple)}
.tc.live::after{content:'';position:absolute;inset:0;border-radius:12px;box-shadow:0 0 28px rgba(129,87,242,0.10);pointer-events:none}
.tc-top-bar{position:absolute;top:0;left:0;right:0;height:2px;border-radius:12px 12px 0 0;background:var(--purple);opacity:0}
.tc.live .tc-top-bar{opacity:1}
.tc-label{font-family:var(--head);font-size:9px;font-weight:700;letter-spacing:.12em;text-transform:uppercase;color:var(--text-3);margin-bottom:4px}
.tc-period{font-family:var(--head);font-size:12px;font-weight:600;color:var(--text-2);margin-bottom:16px}
.tc-row{display:flex;justify-content:space-between;align-items:center;padding:7px 0;border-bottom:1px solid var(--border)}
.tc-row:last-of-type{border-bottom:none}
.tc-row-l{font-size:11px;color:var(--text-3);font-family:var(--body)}
.tc-row-v{font-family:var(--head);font-size:13px;font-weight:600;color:var(--text-1);display:flex;align-items:center;gap:5px}
.tc-badge{margin-top:14px;padding:5px 11px;border-radius:100px;font-size:10px;font-weight:700;font-family:var(--head);letter-spacing:.04em;text-align:center;border:1px solid rgba(129,87,242,0.22);background:rgba(129,87,242,0.08);color:var(--purple-light)}
.tc-badge.green{background:var(--up-bg);color:var(--up);border-color:rgba(93,206,166,0.22)}
.tc-badge.dim{background:rgba(255,255,255,0.03);color:var(--text-3);border-color:var(--border)}
/* delta chips inside tc-row-v */
.delta{font-size:10px;font-weight:600;padding:2px 7px;border-radius:100px;font-family:var(--head)}
.delta.pos{background:var(--up-bg);color:var(--up)}
.delta.neg{background:var(--dn-bg);color:var(--dn)}
.delta.na{background:rgba(255,255,255,0.04);color:var(--text-3);border:1px solid var(--border)}
/* ── COMPETITIVE TABLE ──────────────────────────── */
.comp-wrap{background:var(--surface);border:1px solid var(--border);border-radius:12px;overflow:hidden;margin-bottom:48px}
table{width:100%;border-collapse:collapse}
thead tr{background:rgba(129,87,242,0.06)}
th{padding:11px 18px;text-align:left;font-family:var(--head);font-size:10px;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:rgba(129,87,242,0.80);border-bottom:1px solid var(--border)}
td{padding:14px 18px;font-size:13px;border-bottom:1px solid var(--border);color:var(--text-2);font-family:var(--body)}
tbody tr:last-child td{border-bottom:none}
tbody tr:hover td{background:rgba(129,87,242,0.03)}
tr.hl td{background:rgba(129,87,242,0.05)}
/* rank badges */
.rank-badge{display:inline-flex;align-items:center;justify-content:center;width:24px;height:24px;border-radius:6px;font-family:var(--head);font-size:11px;font-weight:700}
.rank-1{background:rgba(240,112,112,0.12);color:var(--dn)}
.rank-2{background:rgba(255,185,50,0.10);color:#FFB932}
.rank-3{background:rgba(129,87,242,0.15);color:var(--purple-light)}
.rank-other{background:rgba(255,255,255,0.06);color:var(--text-3)}
/* domain names */
.dname{font-family:var(--head);font-size:13px;font-weight:600;color:var(--text-1)}
.dname.me{color:var(--purple)}
.mono{font-family:var(--mono);font-size:12px;color:var(--text-2)}
/* trend badges */
.tbadge{display:inline-flex;align-items:center;padding:3px 9px;border-radius:100px;font-size:10px;font-weight:700;font-family:var(--head);letter-spacing:.03em}
.t-up{background:var(--up-bg);color:var(--up)}
.t-dn{background:var(--dn-bg);color:var(--dn)}
.t-stable{background:rgba(255,255,255,0.05);color:var(--text-3);border:1px solid var(--border)}
.mkt-note{padding:16px 20px;border-top:1px solid var(--border);background:rgba(129,87,242,0.03)}
.mkt-note p{font-size:12px;color:var(--text-2);line-height:1.65}
/* ── TWO-COL ─────────────────────────────────────── */
.two-col{display:grid;grid-template-columns:1fr 1fr;gap:14px;margin-bottom:48px}
.card{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:22px 20px;transition:border-color .2s}
.card:hover{border-color:var(--border-purple)}
.card-ttl{font-family:var(--head);font-size:10px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--text-3);margin-bottom:14px}
/* hero stat */
.big-stat-val{font-family:var(--head);font-size:48px;font-weight:700;line-height:1;margin-bottom:4px}
.big-stat-val.green{color:var(--up)}
.big-stat-val.red{color:var(--dn)}
.big-stat-val.na{color:var(--text-3)}
.big-stat-label{font-size:11px;color:var(--text-3);font-family:var(--body);margin-bottom:18px;line-height:1.4}
/* stat rows */
.srow{display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)}
.srow:last-of-type{border-bottom:none}
.srow-l{font-size:12px;color:var(--text-3)}
.srow-v{font-family:var(--head);font-size:13px;font-weight:600;color:var(--text-1)}
/* content clusters */
.cluster{padding:10px 0;border-bottom:1px solid var(--border)}
.cluster:last-child{border-bottom:none}
.cluster-url{font-family:var(--mono);font-size:11px;color:var(--purple-light);margin-bottom:4px;word-break:break-all}
.cluster-meta{display:flex;gap:14px;font-size:11px;color:var(--text-3)}
.cluster-meta strong{color:var(--text-2);font-weight:500}
/* monthly trend bars */
.trend-row{margin-bottom:12px}
.trend-row:last-child{margin-bottom:0}
.trend-meta{display:flex;justify-content:space-between;align-items:center;margin-bottom:5px}
.trend-month{font-family:var(--head);font-size:11px;font-weight:600;color:var(--text-2)}
.trend-etv{font-family:var(--mono);font-size:11px;color:var(--text-3)}
.trend-track{height:10px;background:rgba(255,255,255,0.05);border-radius:100px;overflow:hidden}
.trend-bar{height:100%;border-radius:100px;background:rgba(129,87,242,0.55)}
/* keyword distribution */
.kw-dist{margin-top:2px}
.kw-row{display:flex;justify-content:space-between;align-items:center;padding:8px 0;border-bottom:1px solid var(--border)}
.kw-row:last-child{border-bottom:none}
.kw-label{font-size:12px;color:var(--text-3)}
.kw-val{font-family:var(--head);font-size:13px;font-weight:600;color:var(--text-1)}
.kw-val.hot{color:var(--up)}
.kw-val.warm{color:var(--purple-light)}
/* ── STRATEGIC PRIORITIES ───────────────────────── */
.strat-shell{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:26px 24px;margin-bottom:48px}
.strat-shell-hdr{display:flex;justify-content:space-between;align-items:center;margin-bottom:22px}
.strat-shell-ttl{font-family:var(--head);font-size:15px;font-weight:600;color:var(--text-1)}
.strat-period-chip{font-family:var(--head);font-size:10px;font-weight:700;padding:4px 12px;border-radius:100px;background:rgba(129,87,242,0.08);color:var(--purple-light);border:1px solid rgba(129,87,242,0.22);letter-spacing:.04em}
.strat-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:12px}
.sc{background:rgba(255,255,255,0.03);border:1px solid var(--border);border-radius:10px;padding:18px 16px;transition:border-color .2s,background .2s}
.sc:hover{border-color:var(--border-purple);background:rgba(129,87,242,0.04)}
.sc-num{font-family:var(--head);font-size:9px;font-weight:700;letter-spacing:.1em;text-transform:uppercase;color:var(--purple);margin-bottom:7px}
.sc-title{font-family:var(--head);font-size:13px;font-weight:600;color:var(--text-1);margin-bottom:9px;line-height:1.3}
.sc-desc{font-size:12px;color:var(--text-2);line-height:1.6}
/* ── EXECUTIVE SUMMARY ──────────────────────────── */
.exec{background:rgba(129,87,242,0.05);border:1px solid rgba(129,87,242,0.18);border-radius:12px;padding:30px 28px;margin-bottom:48px}
.exec-title{display:flex;align-items:center;gap:9px;font-family:var(--head);font-size:15px;font-weight:600;color:var(--purple-light);margin-bottom:20px}
.exec-title::before{content:'';display:inline-block;width:5px;height:5px;border-radius:50%;background:var(--purple);box-shadow:0 0 7px var(--purple);flex-shrink:0}
.exec p{font-size:13px;color:var(--text-2);line-height:1.75;margin-bottom:14px}
.exec p:last-of-type{margin-bottom:22px}
.exec-badge{display:inline-block;background:rgba(129,87,242,0.10);border:1px solid rgba(129,87,242,0.28);border-radius:100px;padding:8px 20px;font-family:var(--head);font-size:11px;font-weight:700;color:var(--purple-light);letter-spacing:.04em}
/* ── FOOTER ─────────────────────────────────────── */
.footer{border-top:1px solid var(--border);padding:20px 0 0;text-align:center;font-family:var(--mono);font-size:11px;color:var(--text-3);line-height:1.7}
/* ── RESPONSIVE ─────────────────────────────────── */
@media(max-width:700px){
.timeline{grid-template-columns:1fr}
.timeline::before{display:none}
.two-col{grid-template-columns:1fr}
.strat-grid{grid-template-columns:1fr 1fr}
}
@media(max-width:460px){.strat-grid{grid-template-columns:1fr}}
</style>
</head>
<body>
<div class="page">
<!-- ── HEADER ─────────────────────────────────── -->
<div class="hdr">
<div class="hdr-pill">
<span class="hdr-pill-dot"></span>
Infrasity · SEO Performance Report
</div>
<div class="hdr-title">Strategic Performance<br><em>{{TARGET_DOMAIN}}</em></div>
<div class="hdr-sub">{{START_DATE}} → {{END_DATE}} · United States · Competitive Set: {{COMP_DOMAIN_LIST}}</div>
<div class="hdr-divider"></div>
</div>
<!-- ── 01 PERFORMANCE TIMELINE ─────────────────── -->
<div class="sec-hdr">
<span class="sec-dot"></span>
<span class="sec-num">01</span>
<span class="sec-label">Performance Timeline</span>
</div>
<div class="timeline">
<!-- Baseline card -->
<div class="tc">
<div class="tc-top-bar"></div>
<div class="tc-label">Baseline</div>
<div class="tc-period">{{START_DATE}}</div>
<div class="tc-row">
<span class="tc-row-l">Monthly Traffic</span>
<span class="tc-row-v">{{BASELINE_TRAFFIC}}</span>
</div>
<div class="tc-row">
<span class="tc-row-l">Organic Keywords</span>
<span class="tc-row-v">{{BASELINE_KEYWORDS}}</span>
</div>
<div class="tc-row">
<span class="tc-row-l">Top 3 Keywords</span>
<span class="tc-row-v">{{BASELINE_TOP3}}</span>
</div>
<div class="tc-row">
<span class="tc-row-l">Competitive Rank</span>
<span class="tc-row-v">#{{BASELINE_RANK}}</span>
</div>
<div class="tc-badge dim">Baseline · {{START_DATE}}</div>
</div>
<!-- Current card (active / highlighted) -->
<div class="tc live">
<div class="tc-top-bar"></div>
<div class="tc-label">Current State</div>
<div class="tc-period">{{END_DATE}}</div>
<div class="tc-row">
<span class="tc-row-l">Monthly Traffic</span>
<span class="tc-row-v">{{CURRENT_TRAFFIC}} <span class="delta {{TRAFFIC_GROWTH_CLASS}}">{{TRAFFIC_GROWTH_PCT}}</span></span>
</div>
<div class="tc-row">
<span class="tc-row-l">Organic Keywords</span>
<span class="tc-row-v">{{CURRENT_KEYWORDS}} <span class="delta {{KEYWORDS_CHANGE_CLASS}}">{{KEYWORDS_CHANGE_PCT}}</span></span>
</div>
<div class="tc-row">
<span class="tc-row-l">Top 3 Keywords</span>
<span class="tc-row-v">{{CURRENT_TOP3}} <span class="delta {{TOP3_GROWTH_CLASS}}">{{TOP3_GROWTH_PCT}}</span></span>
</div>
<div class="tc-row">
<span class="tc-row-l">Competitive Rank</span>
<span class="tc-row-v">#{{CURRENT_COMP_RANK}} of {{TOTAL_COMPETITORS}}</span>
</div>
<div class="tc-badge">Rank #{{CURRENT_COMP_RANK}} Overall</div>
</div>
<!-- Q2 target card -->
<div class="tc">
<div class="tc-top-bar"></div>
<div class="tc-label">Q2 Target</div>
<div class="tc-period">Where We're Going</div>
<div class="tc-row">
<span class="tc-row-l">Monthly Traffic</span>
<span class="tc-row-v">{{TARGET_GOAL_TRAFFIC}}+</span>
</div>
<div class="tc-row">
<span class="tc-row-l">Organic Keywords</span>
<span class="tc-row-v">{{TARGET_GOAL_KEYWORDS}}+</span>
</div>
<div class="tc-row">
<span class="tc-row-l">Top 3 Keywords</span>
<span class="tc-row-v">{{TARGET_GOAL_TOP3}}+</span>
</div>
<div class="tc-row">
<span class="tc-row-l">Target Position</span>
<span class="tc-row-v">{{TARGET_BADGE_TEXT}}</span>
</div>
<div class="tc-badge green">Target: {{TARGET_BADGE_TEXT}}</div>
</div>
</div>
<!-- ── 02 COMPETITIVE LANDSCAPE ─────────────────── -->
<div class="sec-hdr">
<span class="sec-dot"></span>
<span class="sec-num">02</span>
<span class="sec-label">Competitive Landscape</span>
</div>
<div class="comp-wrap">
<table>
<thead>
<tr>
<th>Rank</th>
<th>Domain</th>
<th>Monthly Traffic</th>
<th>Keywords</th>
<th>Q1 Trend</th>
</tr>
</thead>
<tbody>
{{COMP_TABLE_ROWS}}
</tbody>
</table>
<div class="mkt-note">
<p>{{MARKET_INSIGHT_TEXT}}</p>
</div>
</div>
<!-- ── 03 TRAFFIC & CONTENT ──────────────────────── -->
<div class="sec-hdr">
<span class="sec-dot"></span>
<span class="sec-num">03</span>
<span class="sec-label">Traffic & Content</span>
</div>
<div class="two-col">
<!-- Left: Business Impact + Content Clusters -->
<div class="card">
<div class="card-ttl">Business Impact</div>
<div class="big-stat-val {{BIG_STAT_CLASS}}">{{BIG_STAT_VAL}}</div>
<div class="big-stat-label">Traffic change {{START_DATE}} → {{END_DATE}}</div>
<div class="srow">
<span class="srow-l">Competitive Position</span>
<span class="srow-v">#{{CURRENT_COMP_RANK}} of {{TOTAL_COMPETITORS}}</span>
</div>
<div class="srow">
<span class="srow-l">Fastest Growing in Set</span>
<span class="srow-v" style="color:{{FASTEST_GROWING_COLOR}}">{{FASTEST_GROWING_LABEL}}</span>
</div>
<div class="srow" style="margin-bottom:20px">
<span class="srow-l">Gap to Close (#{{RANK_ABOVE}})</span>
<span class="srow-v" style="color:var(--dn)">{{GAP_TO_NEXT}} ETV</span>
</div>
<div class="card-ttl" style="margin-top:2px">Top Content Clusters</div>
<div class="cluster">
<div class="cluster-url">{{PAGE1_URL}}</div>
<div class="cluster-meta"><span>ETV: <strong>{{PAGE1_ETV}}</strong></span><span>Keywords: <strong>{{PAGE1_KW}}</strong></span></div>
</div>
<div class="cluster">
<div class="cluster-url">{{PAGE2_URL}}</div>
<div class="cluster-meta"><span>ETV: <strong>{{PAGE2_ETV}}</strong></span><span>Keywords: <strong>{{PAGE2_KW}}</strong></span></div>
</div>
<div class="cluster">
<div class="cluster-url">{{PAGE3_URL}}</div>
<div class="cluster-meta"><span>ETV: <strong>{{PAGE3_ETV}}</strong></span><span>Keywords: <strong>{{PAGE3_KW}}</strong></span></div>
</div>
</div>
<!-- Right: Monthly Trend Bars + Keyword Distribution -->
<div class="card">
<div class="card-ttl">Monthly Traffic Trend</div>
<div class="trend-row">
<div class="trend-meta">
<span class="trend-month">{{TREND_LABEL_1}}</span>
<span class="trend-etv">{{TREND_ETV_1}}</span>
</div>
<div class="trend-track"><div class="trend-bar" style="width:{{TREND_BAR_WIDTH_1}}%"></div></div>
</div>
<div class="trend-row">
<div class="trend-meta">
<span class="trend-month">{{TREND_LABEL_2}}</span>
<span class="trend-etv">{{TREND_ETV_2}}</span>
</div>
<div class="trend-track"><div class="trend-bar" style="width:{{TREND_BAR_WIDTH_2}}%"></div></div>
</div>
<div class="trend-row">
<div class="trend-meta">
<span class="trend-month">{{TREND_LABEL_3}}</span>
<span class="trend-etv">{{TREND_ETV_3}}</span>
</div>
<div class="trend-track"><div class="trend-bar" style="width:{{TREND_BAR_WIDTH_3}}%"></div></div>
</div>
<div class="trend-row" style="margin-bottom:22px">
<div class="trend-meta">
<span class="trend-month">{{TREND_LABEL_4}}</span>
<span class="trend-etv">{{TREND_ETV_4}}</span>
</div>
<div class="trend-track"><div class="trend-bar" style="width:{{TREND_BAR_WIDTH_4}}%"></div></div>
</div>
<div class="card-ttl">Keyword Distribution (Current)</div>
<div class="kw-dist">
<div class="kw-row">
<span class="kw-label">Position 1</span>
<span class="kw-val">{{KW_POS_1}}</span>
</div>
<div class="kw-row">
<span class="kw-label">Position 2–3</span>
<span class="kw-val">{{KW_POS_2_3}}</span>
</div>
<div class="kw-row">
<span class="kw-label">Position 4–10</span>
<span class="kw-val hot">{{KW_POS_4_10}}</span>
</div>
<div class="kw-row">
<span class="kw-label">Position 11–20</span>
<span class="kw-val warm">{{KW_POS_11_20}}</span>
</div>
<div class="kw-row">
<span class="kw-label">Position 21–100</span>
<span class="kw-val">{{KW_POS_21_100}}</span>
</div>
</div>
</div>
</div>
<!-- ── 04 STRATEGIC PRIORITIES ───────────────────── -->
<div class="sec-hdr">
<span class="sec-dot"></span>
<span class="sec-num">04</span>
<span class="sec-label">Q2 Strategic Priorities</span>
</div>
<div class="strat-shell">
<div class="strat-shell-hdr">
<div class="strat-shell-ttl">6 Data-Driven Actions</div>
<div class="strat-period-chip">Q2 · {{END_DATE}}</div>
</div>
<div class="strat-grid">
<div class="sc">
<div class="sc-num">1. {{STRAT_1_NUM_LABEL}}</div>
<div class="sc-title">{{STRAT_1_TITLE}}</div>
<div class="sc-desc">{{STRAT_1_DESC}}</div>
</div>
<div class="sc">
<div class="sc-num">2. {{STRAT_2_NUM_LABEL}}</div>
<div class="sc-title">{{STRAT_2_TITLE}}</div>
<div class="sc-desc">{{STRAT_2_DESC}}</div>
</div>
<div class="sc">
<div class="sc-num">3. {{STRAT_3_NUM_LABEL}}</div>
<div class="sc-title">{{STRAT_3_TITLE}}</div>
<div class="sc-desc">{{STRAT_3_DESC}}</div>
</div>
<div class="sc">
<div class="sc-num">4. {{STRAT_4_NUM_LABEL}}</div>
<div class="sc-title">{{STRAT_4_TITLE}}</div>
<div class="sc-desc">{{STRAT_4_DESC}}</div>
</div>
<div class="sc">
<div class="sc-num">5. {{STRAT_5_NUM_LABEL}}</div>
<div class="sc-title">{{STRAT_5_TITLE}}</div>
<div class="sc-desc">{{STRAT_5_DESC}}</div>
</div>
<div class="sc">
<div class="sc-num">6. {{STRAT_6_NUM_LABEL}}</div>
<div class="sc-title">{{STRAT_6_TITLE}}</div>
<div class="sc-desc">{{STRAT_6_DESC}}</div>
</div>
</div>
</div>
<!-- ── 05 INFRASITY'S NOTES ───────────────────────── -->
<div class="sec-hdr">
<span class="sec-dot"></span>
<span class="sec-num">05</span>
<span class="sec-label">Infrasity's Notes</span>
</div>
<div class="exec">
<div class="exec-title">Strategic Overview</div>
<p>{{EXEC_PARA_1}}</p>
<p>{{EXEC_PARA_2}}</p>
<p>{{EXEC_PARA_3}}</p>
<p>{{EXEC_PARA_4}}</p>
<div class="exec-badge">{{EXEC_BADGE_TEXT}}</div>
</div>
<!-- ── FOOTER ─────────────────────────────────────── -->
<div class="footer">
Data sourced from DataForSEO (ignore_synonyms: false) · Traffic figures represent estimated organic traffic value (ETV)<br>
Competitive set: {{COMP_DOMAIN_LIST}} · Report period: {{START_DATE}} – {{END_DATE}} · Generated by Infrasity
</div>
</div>
</body>
</html>Related skills
How it compares
Use instead of hand-built spreadsheets or generic analytics exports when you need a fixed 3-month SEO narrative tied to DataForSEO.
FAQ
Who is growth-report for?
SEO practitioners, agencies, and growth or dev-marketing leads who report organic performance to clients or leadership on a monthly or quarterly cadence.
When should I use growth-report?
Use it in Grow analytics when you have a live domain, a competitor list, and need a polished HTML briefing on traffic, rankings, and positioning over about three months.
Is growth-report safe to install?
It calls external SEO APIs with your credentials; review the Security Audits panel on this page and scope DataForSEO keys before cloning the dev-gtm skills repo.