Under construction Sincere is still being built and is not yet active. It will be launched in the upcoming days.

Transparency

How anonymity works.

An anonymous feedback tool only works if people trust it. So instead of asking for trust, here is the exact design: what we store, how the math works, and where the limits are. The source code is public.

The two problems

Anonymity would be trivial if we stored nothing about you. But two rules have to be enforced, and both are about you specifically:

  1. You can only vote once per message.
  2. You can only post once every 24 hours.

The naive implementation stores your Slack user ID next to each vote and each post. Anyone with database access could then deanonymize everything. Sincere enforces both rules without ever writing your user ID to the database.

Keyed tokens instead of identities

The server holds a single secret. It lives only in the server's environment, never in the database and never in backups. Your user ID is run through HMAC-SHA256 with that secret before anything touches disk:

voter_token  = HMAC-SHA256(secret,
                 "vote:" + message_ts + ":" + user_id)

poster_token = HMAC-SHA256(secret,
                 "post:" + user_id)

One vote per message, enforced by the database

Voting twice on the same message produces the same token, and a database uniqueness constraint rejects the second vote. This is enforced by the database itself, not just application code, so two simultaneous clicks can't slip through.

Votes can't be linked to a person, or to each other

The message timestamp is part of the vote hash, so your token on message A and your token on message B share nothing. Even with a full database dump, nobody can tell that the same person voted on two different messages. And only the agree/disagree totals exist. Which way anyone voted is never stored.

Rate limiting without history

Posting claims a single expiring lock row per (hashed) user, overwritten each time, so no history of when you posted builds up. Expired locks are deleted every minute.

No timestamps that give you away

Knowing when a message was submitted is enough to deanonymize its author if anything else shares that timestamp. So:

  • Queued messages store no submission timestamp, only the future posting time, picked at random between 5 seconds and 24 hours after submission.
  • The rate-limit lock's expiry is rounded up to the next full hour, so it can't be matched against a message's posting window.
  • Messages are posted by a scheduler that scans every 60 seconds, by the bot, with no reference to the submitter.
  • Slack request payloads contain your user ID and message text together. We never log them.

What is actually in the database

Table Contents Identity?
messages posted text, Slack timestamp, agree/disagree counters none
message_votes message timestamp + voter token HMAC token only
post_locks poster token + hour-rounded expiry HMAC token only
scheduled_messages text, team ID, random posting time none
installations Slack OAuth data for your workspace workspace-level only, never linked to any message or vote

Where the limits are

We'd rather you know these upfront:

Slack knows you ran /sincere

Slash-command usage is visible to Slack Inc. per their privacy policy. We can only change what we store, not what Slack sees.

The operator plus the secret can test membership

Someone with both the database and the server secret could compute tokens for every member of a workspace and check who voted on a message (not which way), or whether someone posted recently (not what they wrote, since text is never linked to any token). This design protects against leaked databases and backups. It does not protect against a fully malicious operator, and no server-side design can. That is why the secret is kept out of the database and backups.

Small groups leak socially

In a three-person channel, “somebody” is not very anonymous no matter what the database stores. Content itself can also identify its author.

Message text is stored in plaintext

Anonymity here means unlinkable to you, not encrypted.

Verify it yourself

Everything on this page can be checked against the source code: the token construction, the schema, and a test suite that makes sure raw user IDs never reach the database layer. If you find a hole in the design, we want to hear about it.