Blueprints/Build a live polling site

Build a live polling site

A select field, a pie chart, a bar chart. That is the whole poll. Nothing else to it.

Updated March 2026

You need a quick vote on something. Team decision, audience question, social content. Define poll options as a select field, collect anonymous votes, and show results on a public dashboard. The pie chart updates every 30 seconds. No backend, no real-time infrastructure. One form, one dashboard. An agent can set this up end-to-end: create the poll form from template, make the dashboard public, return the voting URL and results URL.

Architecture

ToolRoleCost
Cloudflare PagesStatic site hostingFree
SutrenaVote collection, live results dashboard$9/mo (Builder)

Total cost: $9/mo

Builder starts at $9/month for 50 projects. Pro at $29/month covers 200 projects and all your other work too. Build five blueprints on Pro and it is still $29/month. That is where the value is — at scale.

Each poll is a Sutrena form with a single select field. publicResults is on so anyone can see the dashboard. The dashboard has a pie chart, a bar chart, a total count, and a voting timeline.

Want multiple polls? Make multiple forms. Each gets its own dashboard URL. Build an index page that lists your active polls with links.

Form Definition

One required select field with the poll options. publicResults is on. No uniqueBy for anonymous polls, but you can add it if you want to limit one vote per person.

{
  "name": "Community Poll",
  "fields": [
    {
      "name": "vote",
      "label": "Your Vote",
      "type": "select",
      "options": [
        "Option A",
        "Option B",
        "Option C",
        "Option D"
      ],
      "required": true
    }
  ],
  "publicResults": true
}

Dashboard Definition

Total votes, pie chart for the visual split, bar chart for exact counts, and a timeline of when votes came in. The 30-second auto-refresh makes it feel live enough.

{
  "version": 1,
  "widgets": [
    {
      "type": "metric_card",
      "title": "Total Votes",
      "value": "count(*)"
    },
    {
      "type": "pie_chart",
      "title": "Vote Distribution",
      "groupBy": "vote"
    },
    {
      "type": "bar_chart",
      "title": "Votes by Option",
      "groupBy": "vote"
    },
    {
      "type": "line_chart",
      "title": "Voting Activity",
      "groupBy": "$submitted_at:day"
    }
  ]
}

Frontend Integration

Clickable option cards with a vote button. After voting, users go to the live results dashboard. Replace the form and dashboard IDs with yours.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <title>Community Poll</title>
  <style>
    body { font-family: system-ui, sans-serif; max-width: 480px; margin: 2rem auto; padding: 0 1rem; }
    .option { display: block; padding: 0.75rem 1rem; margin: 0.5rem 0; border: 2px solid #ddd;
      border-radius: 8px; cursor: pointer; transition: border-color 0.2s; }
    .option:hover { border-color: #2563eb; }
    .option.selected { border-color: #2563eb; background: #eff6ff; }
    button { width: 100%; padding: 0.75rem; margin-top: 1rem; font-size: 1rem;
      cursor: pointer; background: #111; color: #fff; border: none; border-radius: 8px; }
    button:disabled { opacity: 0.5; cursor: not-allowed; }
  </style>
</head>
<body>
  <h1>What should we build next?</h1>
  <p>Pick one option. Results update live.</p>

  <div id="options">
    <label class="option"><input type="radio" name="vote" value="Option A" hidden /> Option A</label>
    <label class="option"><input type="radio" name="vote" value="Option B" hidden /> Option B</label>
    <label class="option"><input type="radio" name="vote" value="Option C" hidden /> Option C</label>
    <label class="option"><input type="radio" name="vote" value="Option D" hidden /> Option D</label>
  </div>
  <button id="vote-btn" disabled>Vote</button>
  <p id="status"></p>
  <p><a href="https://sutrena.com/d/dsh_YOUR_DASHBOARD_ID">See live results</a></p>

  <script>
    const FORM_ID = "frm_YOUR_FORM_ID";
    let selected = null;

    document.querySelectorAll(".option").forEach((label) => {
      label.addEventListener("click", () => {
        document.querySelectorAll(".option").forEach((l) => l.classList.remove("selected"));
        label.classList.add("selected");
        selected = label.querySelector("input").value;
        document.getElementById("vote-btn").disabled = false;
      });
    });

    document.getElementById("vote-btn").addEventListener("click", async () => {
      if (!selected) return;
      document.getElementById("vote-btn").disabled = true;

      const res = await fetch(
        `https://sutrena.com/api/forms/${FORM_ID}/submit`,
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ vote: selected }),
        }
      );

      document.getElementById("status").textContent = res.ok
        ? "Vote recorded. Check the live results."
        : "Something went wrong. Try again.";
    });
  </script>
</body>
</html>

FAQ

Can someone vote multiple times?

With no uniqueBy, yes. Sutrena rate-limits per IP to slow down rapid abuse. For stricter controls, add uniqueBy or require auth. Depends on how much you care about accuracy.

How do I create multiple polls?

One form per poll, each with its own dashboard. Build an index page with links to all active polls. Nothing fancy.

Can I close a poll after a deadline?

Set closesAt to an ISO datetime. After that, the form returns 410 Gone. The results dashboard stays viewable.

Can I customize the poll options after creation?

Yes. PATCH the form to update the options array. Existing votes stay. New submissions validate against the updated list.

What is Sutrena?

Sutrena is the web runtime for AI agents. Three primitives — pages, forms, and dashboards — accessible through one API. Your agent creates web artifacts, humans interact with them, and your agent gets the data back. Framework-agnostic. Works from any MCP client or HTTP client.

Get started in two API calls

1. Get a trial key (no auth, no signup)

curl -X POST https://sutrena.com/api/trial

2. Create a form + dashboard from a template

curl -X POST https://sutrena.com/api/forms \
  -H "Authorization: Bearer st_trial_xxx" \
  -H "Content-Type: application/json" \
  -d '{"templateId": "waitlist", "createDashboard": true}'

Ready to build?

Get a trial API key instantly with no signup, or create an account for the full experience.

Build a live polling site — Sutrena | Sutrena