Voter Receipts and Ballot Verification

Give your voters confidence that their ballot was counted. Receipt codes provide cryptographic proof of inclusion without revealing how anyone voted.

What is a Receipt Code?

A receipt code is a 12-character cryptographic identifier generated when a voter submits their ballot. It is computed on the server using HMAC-SHA256, a keyed hash function that takes the ballot's unique ID and a server-side secret as inputs.

The resulting code (e.g., A7F3B9C2E1D4) serves as a fingerprint for that specific ballot. It is unique, deterministic, and cannot be reversed to reveal the ballot contents.

Each receipt code is enforced as unique at the database level. No two ballots can share the same code.

How Voters See Their Receipt

After a voter clicks "Submit Vote," the server records the encrypted ballot and generates the receipt code. The voter then sees a Vote Confirmed screen that displays their unique receipt code.

Voters should save this code for their records. It is the only way for them to independently verify their ballot later. The code is shown once on the confirmation screen and is not stored anywhere the voter can retrieve it afterward.

Tip: Remind your voters to write down or screenshot their receipt code immediately after voting. You can include this reminder in your invitation emails or pre-meeting communications.

How Receipts Preserve Anonymity

VoteAlly uses a strict separation between voter identity and ballot content. The receipt code is derived from the ballot ID only, not from the voter's identity or their vote choices.

The Ballot record in the database has no reference to the voter who cast it. Voter participation (who voted on which question) is tracked in a separate table. This architectural split means that even with full database access, there is no direct path from a receipt code to a voter's identity or from a voter to their specific ballot.

Additional protections reinforce this separation:

  • Timestamp decoupling: Ballot timestamps are rounded down to the nearest hour to prevent time-based correlation between a voter's participation record and a ballot.
  • Encrypted ballot contents: The actual vote choices are encrypted with AES-256-GCM. The plaintext selection is never stored.
  • HMAC-based tallying: Vote counts use hashed candidate identifiers, so the database engine never sees which candidate received which votes in readable form.

Exporting the Ballot Audit CSV

Administrators can download a Ballot Audit CSV that lists every ballot recorded for a session. This file is designed for transparency: you can publish it so voters can verify their ballots were counted.

1

Navigate to the Reports tab

Open the voting session in your admin dashboard and go to the Reports tab.

2

Click "Export Ballot Audit"

This downloads a CSV file containing every ballot in the session.

3

Review the CSV columns

The file includes: BallotID, ReceiptCode, Timestamp, QuestionID, and QuestionTitle. It does not include voter names, emails, or vote choices.

4

Publish or share the receipt code list

Share the ReceiptCode column with your membership. Voters can search the list for their code to confirm their ballot was included in the final tally.

Important: The export action is logged in the audit trail. The log records who exported the file, when, and how many ballot records were included.

How a Voter Verifies Their Ballot

Once you publish the Ballot Audit CSV (or the ReceiptCode column from it), any voter can verify their ballot independently:

  1. The voter locates the receipt code they saved after voting.
  2. They search the published list for their code (e.g., using Ctrl+F in a spreadsheet or text file).
  3. If the code appears, their ballot is confirmed as part of the official tally.
  4. If the code does not appear, they should contact the administrator for investigation.

Key point: The published list only contains receipt codes and question titles. It does not reveal who cast which ballot or what choices were made. This makes it safe to share publicly.

Receipts Survive PII Purging

VoteAlly automatically purges voter Personally Identifiable Information (PII) after a configurable retention period (90 days by default). When this happens, voter names, emails, phone numbers, and candidate photos are permanently removed.

Receipt codes are not affected by PII purging. They are stored on the Ballot record, which is structurally separate from voter data. Because the Ballot table has no reference to the voter who cast it, ballots and their receipt codes persist indefinitely as part of the permanent audit trail.

Removed by PII Purge
  • Voter names and emails
  • Phone numbers and member IDs
  • Access codes and magic link tokens
  • Candidate photos (from R2 storage)
Preserved After Purge
  • All ballot records and receipt codes
  • Encrypted vote choices
  • Candidate names (public record)
  • Vote weights and participation counts

Frequently Asked Questions

Can a receipt code reveal how someone voted?

No. The receipt code is a one-way cryptographic hash of the ballot ID. It proves that a specific ballot exists in the system, but it cannot be reversed to reveal the vote choices. Ballot contents are encrypted separately using AES-256-GCM.

Can two voters receive the same receipt code?

No. Each ballot generates a distinct HMAC hash, and a unique database constraint prevents collisions. Every receipt code in the system maps to exactly one ballot.

Can a voter forge a receipt code?

No. Receipt codes are generated on the server using HMAC-SHA256 with a secret key that is never exposed to clients. Without access to this secret, it is computationally infeasible to produce a valid receipt code.

What happens to receipt codes after PII is purged?

Receipt codes remain intact. They are stored on the Ballot record, which is structurally separate from voter PII. The purge process removes voter names, emails, and phone numbers, but all ballot data persists as part of the permanent audit trail.

Does the Ballot Audit CSV contain voter names or vote choices?

No. The Ballot Audit CSV contains only the BallotID, ReceiptCode, Timestamp, QuestionID, and QuestionTitle. It is designed to be safe for public distribution.

What should a voter do if their receipt code is missing from the published list?

They should contact the administrator. A missing receipt code could indicate that the voter did not see the "Vote Confirmed" screen (meaning their submission did not complete) or that there was a technical issue. The admin can check the audit trail for details.

Related Guides