How to build an upvote system for feature requests in Notion
Notion doesn't have a voting feature, so you build one out of two properties and a formula. Add a Person property to your feature request database, let people tag themselves in it to vote, then add a Formula property that counts how many names are in that field. Sort the view by the formula, descending, and you have a ranked backlog. Notion's own guide to this pattern confirms there's no shortcut: the formula they publish is prop("Upvoted by").length(), counting names tagged in a Person property called "Upvoted by."
That's the whole mechanism, and it works. The part worth being honest about upfront: a Person property can only hold people who are already members of your Notion workspace. Whoever isn't in the workspace can't be tagged, which means they can't vote, no matter how much they want the feature.
Step 1: build the request database
Start with a plain database. Four properties do the job:
- Name: the request, written as a sentence, not a title fragment
- Status: a select property: Under review, Planned, Shipped
- Asked by: a Created by property, which Notion fills in automatically with whoever created the row
- Upvoted by: a Person property, empty by default
The Asked by and Upvoted by split matters. Without it, the creator's vote and everyone else's votes look identical, and you lose the ability to tell "one person cares a lot" from "six people asked."
Step 2: write the counting formula
Add a Formula property, and set it to:
prop("Upvoted by").length()This counts the number of names in the "Upvoted by" property and returns it as a number. The person who filed the request should tag themselves in "Upvoted by" too, so their own request starts at a vote of one instead of zero.
To vote, a teammate opens the row and adds their name to "Upvoted by." That's the entire voting interaction. No button, no separate form, one property edit.
Step 3: sort and filter the view
A vote count with no view discipline around it is just a number nobody looks at. Build one view that:
- Sorts by the formula property, descending
- Filters Status to hide Shipped (a shipped item with 40 votes clutters the top of the list for no reason)
- Groups by Status if you're tracking more than about thirty open requests
This is the view you actually check before a planning meeting. The formula and the properties behind it exist only to make this one sortable list honest.
A rollup version, if requests and votes need to live apart
The Person-property formula above works as long as one database holds everything. Some teams want an audit trail of individual votes, or want to enforce one vote per person somewhere that isn't a simple tag. For that, use two databases instead of one: a Requests database and a Votes database, connected by a Relation property, with a Rollup on Requests that counts the related Votes rows.
It's more setup for the same number displayed at the end, so most teams should start with the single-database formula in Step 2 and only split into a relation and rollup if they specifically need per-vote records, like a timestamp or a note on why someone voted.
One thing a rollup doesn't fix: a Votes database is still a Notion database, and adding a row to it still requires the person doing the voting to have access to that database. The membership ceiling doesn't move just because you added a second table.
Worked example: a scheduling tool's internal request board
Renee Okafor runs product at Shiftline, a shift-scheduling tool for retail chains with about a dozen people on the product and engineering team. She built the Person-property version above in an afternoon.
"It fixed the exact thing that was broken," Renee said. "Before this, 'popular' meant whichever engineer's Slack DM I'd read most recently. Now I can sort by votes before a planning meeting and actually see it."
The board worked well internally for about two months. Then a customer success manager asked if she could send the board link to an enterprise account that had been asking for the same integration for a quarter.
"I said sure, then realized the second I shared it, they'd hit a login wall," Renee said. "And even if I added them as a guest, all they could do was look. They couldn't tag themselves in a Person property, because they're not a member of our workspace and never will be. So the board keeps counting how loud we are internally about a request, not how many customers actually asked for it."
She tried a Notion form as a workaround, so the customer could at least submit the request without an account. It solved intake, not voting: a Notion form connects to a database, and every response it collects lands as its own row in a Table view. A form has no way to find an existing row and edit one of its properties, only to write a new one, so it can't add a submitter's name to the "Upvoted by" field on a request that already exists. Ten customers filling out the same form produce ten separate rows, not one row with a vote count of ten.
Where the workspace-only ceiling shows up
Two Notion mechanics, both true regardless of how the database is built:
- Person properties only hold workspace members. Notion is explicit that a Person property tags "a person or group from your Notion workspace," with no external-voter mode.
- Forms create rows; they don't add votes to existing ones. A public form is the right tool for intake from people outside the workspace. It is not a way to let them vote on a request someone else already filed.
Put together, this is a request board that ranks by who works at your company and happens to check it, not by who's actually asking. The requests coming in from support tickets, sales calls, and the Slack channels your customers are already in never reach the Person property at all, because nobody is going to open Notion, find the matching row, and tag themselves in it. Most of them just don't.
Where Modem picks up
This is the point where a Notion-native vote count and a real signal of customer demand pull apart. Modem reads feature requests out of Slack, support tickets, and sales calls directly, matches multiple mentions of the same ask to a single counted topic even when nobody typed the same words twice, and keeps every requester attached to it, whether or not they've ever opened your Notion workspace. The count that matters is "how many separate customers and accounts asked," not "how many teammates remembered to tag themselves."
Modem's Notion integration can write those counted topics back into your workspace as pages and database rows, with your approval, so the board format survives and only the source of the number changes. Related reading: the six best tools to sync customer feedback to Notion compares the wider field, and why feature voting boards fail covers the failure modes that show up once a board like this has been running for a year, Notion-built or otherwise. Modem is what we sell, so weigh that bias into the comparison. It doesn't undercut the case for the setup above, since a team ranking only its own internal backlog doesn't need anything more than the Person-property formula.
Set this up before your next planning meeting
Add "Upvoted by" as a Person property and one Formula property with prop("Upvoted by").length() to whatever database already holds your feature requests. Sort by it, descending. That's the entire native system, and it will tell your team more about its own backlog by Friday than a quarter of scattered Slack DMs did.
