Step 3
Get the election.
Before showing the voter login form, load the election attached to your public key. This tells your app whether the election is live, remote, and configured for API voting.
Is the request successful?
If status is false, show the API message and stop the flow.
Is this a remote election?
This starter guide is remote-only, so votingMode must be remote.
Is API voting enabled?
accessMode must be api before a custom frontend can continue.
Is the election live?
Only show the voter login form when the election status is live.
The election object controls the UI.
For this beginner guide, we only continue when the election is a remote API election and its status is live.
{
"status": true,
"data": {
"election": {
"title": "SRC General Elections 2026",
"institution": "CrownVote Demo Institution",
"description": "Official voting event for the SRC General Elections.",
"instructions": "Login with your voter ID and password to cast your vote.",
"status": "live",
"startsAt": "2026-06-01T08:00:00.000Z",
"endsAt": "2026-06-01T17:00:00.000Z",
"votingMode": "remote",
"accessMode": "api",
"inPersonRequireAdminLogin": null,
"inPersonRequireVoterPassword": null
}
}
} Add getElection() to index.js.
This function loads the election, updates the page title and description, checks the election mode, and reveals the voter login form only when the election is ready.
async function getElection() {
hideNotice()
const response = await fetch(`${API_URL}/election`, {
headers: {
'X-PUBLIC-KEY': PUBLIC_KEY,
},
})
const result = await response.json()
if (!result.status) {
showNotice(result.message || 'Unable to load election.')
return
}
state.election = result.data.election
elements.title.textContent = state.election.title
elements.description.textContent =
state.election.description || state.election.instructions || 'Login to cast your vote.'
if (state.election.votingMode !== 'remote') {
showNotice('This starter guide is for remote voting only.')
return
}
if (state.election.accessMode !== 'api') {
showNotice('This election is not configured for API voting.')
return
}
if (state.election.status !== 'live') {
showNotice('This election is not currently live.')
return
}
elements.loginForm.classList.remove('hidden')
}
getElection() Your index.js should now look like this.
Replace cv_pub_xxxxx with the public key from your CrownVote election.
const API_URL = 'https://api.crownvote.com/api/v1'
const PUBLIC_KEY = 'cv_pub_xxxxx'
const state = {
election: null,
accessToken: null,
ballots: [],
selections: {},
}
const elements = {
title: document.querySelector('#electionTitle'),
description: document.querySelector('#electionDescription'),
notice: document.querySelector('#notice'),
loginForm: document.querySelector('#loginForm'),
voterId: document.querySelector('#voterId'),
password: document.querySelector('#password'),
ballotScreen: document.querySelector('#ballotScreen'),
voterInfo: document.querySelector('#voterInfo'),
ballots: document.querySelector('#ballots'),
submitVote: document.querySelector('#submitVote'),
}
function showNotice(message) {
elements.notice.textContent = message
elements.notice.classList.remove('hidden')
}
function hideNotice() {
elements.notice.textContent = ''
elements.notice.classList.add('hidden')
}
async function getElection() {
hideNotice()
const response = await fetch(`${API_URL}/election`, {
headers: {
'X-PUBLIC-KEY': PUBLIC_KEY,
},
})
const result = await response.json()
if (!result.status) {
showNotice(result.message || 'Unable to load election.')
return
}
state.election = result.data.election
elements.title.textContent = state.election.title
elements.description.textContent =
state.election.description || state.election.instructions || 'Login to cast your vote.'
if (state.election.votingMode !== 'remote') {
showNotice('This starter guide is for remote voting only.')
return
}
if (state.election.accessMode !== 'api') {
showNotice('This election is not configured for API voting.')
return
}
if (state.election.status !== 'live') {
showNotice('This election is not currently live.')
return
}
elements.loginForm.classList.remove('hidden')
}
getElection()What you have now
Your app can now contact CrownVote, load the election, confirm it is suitable for this remote starter, and show the voter login form when voting is available.