Skip to content
VoteFirst Docs
Dashboard

Embed

Embed quickstart

A live roadmap in one of your own pages, in three steps. Everything here is copy and paste, and none of it needs a build step or a server.

  1. Get your embed key

    Open the dashboard, choose your project, and go to Share & Embed. The embed key is the first thing on the page. Copy it, along with your project slug, which is the name in the address bar of your board.

    The key is meant to be visible. It opens what your public board already shows and nothing more.

  2. Add the script

    Put these two lines wherever your page loads its scripts, then call init once with the two values you just copied.

    In your page
    <link rel="stylesheet" href="https://app.votefirst.app/embed/votefirst.css">
    <script src="https://app.votefirst.app/embed/votefirst.js"></script>
    <script>
      VoteFirst.init({
        project: 'your-project-slug',
        key: 'your-embed-key'
      });
    </script>

    The stylesheet is optional. Leave it out and the widgets arrive with no styling at all, which is what you want if you would rather write every rule yourself.

    The script tag can also carry the two values itself, which saves the init call entirely.

    The same thing, without a script of your own
    <script src="https://app.votefirst.app/embed/votefirst.js"
            data-project="your-project-slug"
            data-key="your-embed-key"></script>
  3. Mount a widget

    Add an empty element where the board should appear, and name it in one call.

    In your page
    <div id="votefirst-roadmap"></div>
    
    <script>
      VoteFirst.roadmap('#votefirst-roadmap');
    </script>

    That is the whole integration. Load the page and your columns, cards and vote controls are there, reading live from your project.

The whole page

The three steps together, as one file you can save and open.

index.html
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <title>Our roadmap</title>
  <link rel="stylesheet" href="https://app.votefirst.app/embed/votefirst.css">
</head>
<body>
  <h1>Our roadmap</h1>
  <div id="votefirst-roadmap"></div>

  <script src="https://app.votefirst.app/embed/votefirst.js"></script>
  <script>
    VoteFirst.init({
      project: 'your-project-slug',
      key: 'your-embed-key'
    });
    VoteFirst.roadmap('#votefirst-roadmap');
  </script>
</body>
</html>

Your embed key

The key identifies your project to the widgets. It is public by design the way any browser side key is: it has to reach every visitor's browser to be of any use, so nothing behind it can be secret.

An embed key is not an API key. An API key is the opposite kind of credential, a secret that opens every administrative route, and it must never appear in a page. The API sends no cross origin headers to a request carrying one, so a browser cannot complete that request anyway.

Restricting it to your own sites

Under Share & Embed you can list the origins allowed to use the key, one per line or separated by commas. Leave the list empty and any site may embed your board, which is often what a public roadmap wants.

EntryWhat it allows
https://example.comThat origin alone. The scheme and the port have to match as well.
example.comThe same thing. A bare host is read as https, because that is what somebody typing a domain into an allowlist means.
https://*.example.comIts subdomains, and not the bare domain. Add the bare domain as a second entry if you want both.
http://localhost:3000Your own machine while you are building the page. A port is part of an origin, so this and http://localhost:5173 are two entries.
*Every origin, stated rather than implied. The same reach as an empty list.

Each entry is reduced to the form a browser sends, a lowercase scheme and host with an optional port and nothing after it, and anything that could not be a host is dropped rather than stored. That is why the box shows you something other than what you typed after you save: it is showing you what was kept.

This restricts browsers only. A browser refused this way gets origin_not_allowed and a 403, and a request sent from a terminal carries whatever origin its author types, so the allowlist keeps your key from working on somebody else's site rather than making it a secret.

Rotating the key

Rotating stops every page still carrying the old key until its snippet is updated, so do it when a key has ended up somewhere it should not be. Votes, comments and suggestions already recorded are untouched.

What the key may spend

Per project, 3000 reads, 600 writes and 300 new voters a minute, and every page carrying your key draws from the same budget. Rendering a board is three reads, so those numbers are the size of an audience rather than the size of a person. Over any of them the request answers 429 and names the wait in Retry-After.

Pinning a version

The script address above is the stable channel. It is cached for five minutes, so fixes reach your page without you editing anything.

A version pinned address is also served, cached for a year, for anyone who would rather review an upgrade than receive one.

Pinned to one release
https://app.votefirst.app/embed/2.5.4/votefirst.js

Next