NonpartisanIndependent, data-first coverage of US elections — polls, forecasts, and prediction markets, refreshed daily.Updated daily.What's new·Methodology·Send feedback
Embed integration

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).

1 · Pick the widget

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.

2 · Paste the iframe

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>
3 · (Optional) auto-resize

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.

Widget reference

/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.

Sizes: 320×140 (badge) · 480×220 (default) · 720×280 (large)
Query parameters
paramvaluesnote
themelight · dark · autoDefaults to auto (follows prefers-color-scheme).
ratingtrue · falseShow the editorial rating chip. Default true.
sparktrue · falseShow the 30-day poll-average sparkline. Default true.
Example
<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.

Sizes: 240×120 (sm) · 400×200 (md) · 640×360 (lg)
Query parameters
paramvaluesnote
sizesm · md · lgCard size. Default md.
themelight · dark · newsprintDefaults to auto.
Example
<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.

Sizes: 320×120 · 480×180
Query parameters
paramvaluesnote
themelight · dark · autoDefaults to auto.
window30d · 60d · 90d · 6mo · 1yAggregation window. Default 30d.
Example
<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.

Sizes: 320×160 · 480×220
Query parameters
paramvaluesnote
themelight · dark · autoDefaults to auto.
Example
<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.

Sizes: 480×180 (default) · 720×260 (large)
Query parameters
paramvaluesnote
chambersenate · house · governorPath segment, not a query param.
themelight · dark · autoDefaults to auto.
Example
<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).

Sizes: 720×440 (default) · 1080×680 (full bleed)
Query parameters
paramvaluesnote
chambersenate · governorPath segment. House map TBD.
themelight · dark · autoDefaults to auto.
Example
<iframe src="https://poliagg.com/embed/map/senate?theme=light"
        width="100%" height="780" frameborder="0"
        data-pa-embed="senate-map"></iframe>
Theming

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).

Attribution + licensing

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.

Caching + freshness

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.

Troubleshooting
  • 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 height attribute to match the largest size in the widget's sizes line.
  • Dark mode looks wrong — try forcing ?theme=light or ?theme=dark to bypass the auto-detect. Some embedded contexts don't expose prefers-color-scheme.
  • CSP / sandbox errors — our iframes don't require allow-scripts for the visual widget, but auto-resize needs allow-scripts on the iframe to postMessage out.