How to embed PoliAgg widgets
Five widget types · light + dark themes · auto-resize · no API key. Drop an iframe in your post and you're done. Attribution back to PoliAgg is required (CC BY-SA 4.0).
Head to the embed picker and search for any race, topic, or pollster. Or use one of the chamber-control / map embeds linked below. Each kind has its own dedicated section on this page with sizes, query params, and a copy-paste snippet.
Drop the snippet anywhere HTML is allowed — WordPress shortcodes, Ghost / Substack HTML blocks, MDX, plain static sites. The widget is fully self-contained, with no JS dependencies on your end.
<iframe src="https://poliagg.com/embed/race/us-senate-2026-pa?theme=light"
width="480" height="220"
frameborder="0"
data-pa-embed="us-senate-2026-pa"
title="2026 PA Senate · PoliAgg"></iframe>Widgets emit a postMessage event with their content height every time they re-render. Paste this script anywhere on the host page to auto-resize all iframes that carry a data-pa-embed attribute:
<script>
window.addEventListener("message", function (e) {
if (!e.data || e.data.type !== "pa-embed-resize") return;
document.querySelectorAll('iframe[data-pa-embed]').forEach(function (f) {
if (f.src && f.src.indexOf(e.data.path) !== -1) f.style.height = e.data.height + "px";
});
});
</script>Without the script the iframe simply uses whatever height you set. Auto-resize is opt-in — there's nothing you have to do server-side.
/embed/race/{slug}
One race: editorial-rating chip, current poll average, 30-day sparkline, candidate names + party, last-poll date. The smallest size shows just the rating + average; larger sizes include the sparkline and trend.
| param | values | note |
|---|---|---|
theme | light · dark · auto | Defaults to auto (follows prefers-color-scheme). |
rating | true · false | Show the editorial rating chip. Default true. |
spark | true · false | Show the 30-day poll-average sparkline. Default true. |
<iframe src="https://poliagg.com/embed/race/us-senate-2026-pa?theme=light"
width="480" height="220" frameborder="0"
data-pa-embed="us-senate-2026-pa"></iframe>/embed/candidate/{slug}
One candidate's scorecard: polling average, market-implied win probability, net favorability, and FEC money raised — plus the independence grade for candidates with a curated dossier. Links to the full public-record profile.
| param | values | note |
|---|---|---|
size | sm · md · lg | Card size. Default md. |
theme | light · dark · newsprint | Defaults to auto. |
<iframe src="https://poliagg.com/embed/candidate/roy-cooper?size=md&theme=light"
width="426" height="226" frameborder="0"
data-pa-embed="roy-cooper"></iframe>/embed/topic/{id}
One topic: latest national reading from the topic-polls aggregator, with poll-count and source attribution. Useful for embedding issue-tracking widgets (abortion, immigration, economy, etc.) on long-form posts.
| param | values | note |
|---|---|---|
theme | light · dark · auto | Defaults to auto. |
window | 30d · 60d · 90d · 6mo · 1y | Aggregation window. Default 30d. |
<iframe src="https://poliagg.com/embed/topic/abortion?theme=light"
width="480" height="180" frameborder="0"
data-pa-embed="abortion"></iframe>/embed/pollster/{id}
One pollster scorecard: partisan-lean badge, AAPOR transparency badge, rolling Brier vs final results, poll count over the indexed cycles. Use this on "about our methodology" pages or methodology debates.
| param | values | note |
|---|---|---|
theme | light · dark · auto | Defaults to auto. |
<iframe src="https://poliagg.com/embed/pollster/marist?theme=light"
width="480" height="220" frameborder="0"
data-pa-embed="marist"></iframe>/embed/control/{chamber}
Chamber control percentages: P(D control), P(R control), P(tied) for Senate / House / Governors. Renders as a stack bar + serif percentages with the expected D-seat point estimate.
| param | values | note |
|---|---|---|
chamber | senate · house · governor | Path segment, not a query param. |
theme | light · dark · auto | Defaults to auto. |
<iframe src="https://poliagg.com/embed/control/senate?theme=light"
width="100%" height="220" frameborder="0"
data-pa-embed="senate"></iframe>/embed/map/{chamber}
Senate or Governors state map colored by current call (safe / lean / tossup). Hover a state for the rating + candidates. House map uses district hex grid (coming soon).
| param | values | note |
|---|---|---|
chamber | senate · governor | Path segment. House map TBD. |
theme | light · dark · auto | Defaults to auto. |
<iframe src="https://poliagg.com/embed/map/senate?theme=light"
width="100%" height="780" frameborder="0"
data-pa-embed="senate-map"></iframe>Every widget supports ?theme=light, ?theme=dark, and ?theme=auto (default — follows the visitor's OS-level prefers-color-scheme). The widget renders on a transparent background so it picks up whatever your post's surface color is.
Color tokens match the rest of PoliAgg: D = , R = , I = , tossup = . Editorial ratings use the same nine-bucket palette (safe / likely / lean / tilt → tossup → tilt / lean / likely / safe).
Embeds carry a "PoliAgg" link in their bottom-right corner. Please leave it in place — it satisfies the CC BY-SA 4.0 attribution requirement that flows down from Wikipedia / pollster data. If the corner mark breaks your layout, link to poliagg.com nearby in the post body and we'll consider that compliant.
No API key. No rate limit (within reason — please don't refresh-loop). Reach out via /contact if you need a custom widget size, a chart variant we don't offer yet, or a higher-throughput data feed.
Widgets re-fetch their slice of /data/*.json on every page load and are CDN-cached for ~5 minutes. Polls / market quotes / external ratings refresh as the production pipeline lands new data (typically every 15–60 min during active cycles). The widget does not refresh in-place — it picks up new data on the next host-page load.
- Blank iframe — make sure the slug exists. Try opening the embed URL directly in a new tab; you should see the widget. If you see a 404, the slug isn't in our dataset.
- Wrong height / clipped content — paste the auto-resize script above, or bump the
heightattribute to match the largest size in the widget's sizes line. - Dark mode looks wrong — try forcing
?theme=lightor?theme=darkto bypass the auto-detect. Some embedded contexts don't exposeprefers-color-scheme. - CSP / sandbox errors — our iframes don't require
allow-scriptsfor the visual widget, but auto-resize needsallow-scriptson the iframe to postMessage out.