Migrating feedback tools: keep votes, authors, and history

Give the person accepting a feedback migration evidence of what transferred, what changed, and which exceptions still need a decision.

Two navy modular structures linked by continuous threads and small beads, representing preserved votes and context during feedback migration.

When a product team changes its feedback platform, someone needs to sign off on the handover. A screen full of imported requests is weak evidence: it does not show whether authorship, individual votes, private comments, and release links survived. The team needs a record of what transferred, what changed, and which exceptions it accepted.

Before switching tools, define what must survive: authorship, individual votes, dates, access rules, and the links between requests, comments, and announcements. Verify those properties against an untouched export. A successful import message tells you that a job ran; reconciliation tells you what arrived.

Start with an inventory of records and relationships

List the objects your team actually uses. Feedback may include requests, authors, voters, comments, attachments, boards, statuses, and merged duplicates. A changelog adds publication dates, language versions, audience restrictions, and links back to delivered requests. Write down which relationships the destination can represent before choosing a transfer method.

Keep a mapping from each source ID to its destination ID. Titles are poor identifiers: customers can submit identical titles, and teams rename requests. Store the original ID alongside the source tool and object type in your migration records. Use that mapping when attaching a comment to a request or connecting a release announcement to the work it shipped.

Also distinguish the person who authored a request from its internal owner. A team member who manages the migration should not accidentally become the author of every customer suggestion. When identity cannot be resolved, record the uncertainty rather than guessing from a display name.

Check what each export route really contains

CSV, API, and RSS describe transfer mechanisms with different coverage. A CSV can contain full records or only a filtered view. An API can expose details absent from a spreadsheet while excluding some records from its list endpoint. Treat RSS as a publication feed until its contents demonstrate otherwise; do not assume it includes drafts, private feedback, or voter identities.

Canny documents a post export containing vote and comment counts, author information, dates, and other fields, with a separate voter-list export. Its newer Ideas export follows the selected view, omits hidden fields and individual insight details, and has a 10,000-record limit. Identify which product view your team uses before promising coverage.

Featurebase’s Request export covers records across the workspace rather than the currently filtered list. Individual Requesters use a separate export. Its CSV import documentation explicitly distinguishes an imported upvote total from the people behind those votes. Preserving a number does not reconstruct an audience you can contact.

Reading and writing capabilities also differ. Canny’s CSV importer imports a limited set of post fields and attributes imported posts to the uploading admin; its documentation points to the API for authorship, votes, and comments. Check the destination’s accepted fields, not just what the source can export.

Find omissions before the old account closes

Changelogfy illustrates why endpoint coverage matters. Its post list endpoint returns published posts but excludes drafts, future-scheduled, expired, and segment-restricted posts. The single-post endpoint can return drafts when you already know their IDs. That does not make the list a complete inventory.

Its feedback list excludes items pending moderation, while returning hidden feedback under an admin token. Compare the API result with an authorized administrative inventory and obtain a supported export for unresolved gaps. Do not remove audience restrictions just to make records appear in a list.

The authentication documentation specifies API access on Pro and above, 120 requests per minute per authenticated user, and 25 records per paginated page. Locked workspaces, including expired trials or canceled subscriptions, receive 403 responses. Verify access and finish the extraction before canceling the source subscription. These documented details were checked on October 7, 2026; recheck them before your migration.

A worked example of reconciliation

Consider a fictional project-management SaaS whose customers requested approval workflows and more granular role permissions. The team is moving 120 requests and 18 announcements, including a release linked to the approval-workflow request. Its inventory also contains 310 individual vote relationships, 86 comments, and eight release-to-request links. These are illustrative numbers, not vendor benchmarks.

The trial import reports 120 requests and a total score of 310, but the reviewer finds only 295 identified vote relationships. The handover records the remaining 15 as unresolved historical votes rather than inventing users. Two announcements about restricted permissions remain drafts until audience controls pass testing. The person accepting the migration can now see exactly what still requires a decision.

Swipe the table to see other products.

Example acceptance record for the trial migration
CriterionSource evidenceDestination checkDecision
Requests— Source evidence: 120 distinct IDs. Destination check: 120 mapped IDs. Decision: Pass after content review.
Not verified
120 distinct IDs
Not verified
120 mapped IDs
Not verified
Pass after content review
Individual votes— Source evidence: 310 relationships. Destination check: 295 identified; 15 unresolved. Decision: Investigate before claiming full fidelity.
Not verified
310 relationships
Not verified
295 identified; 15 unresolved
Not verified
Investigate before claiming full fidelity
Comments— Source evidence: 86, including private comments. Destination check: 86 with matching parents and visibility. Decision: Pass after access tests.
Not verified
86, including private comments
Not verified
86 with matching parents and visibility
Not verified
Pass after access tests
Announcements— Source evidence: 18 with original dates. Destination check: 16 ready; two restricted drafts. Decision: Hold restricted items.
Not verified
18 with original dates
Not verified
16 ready; two restricted drafts
Not verified
Hold restricted items
Release links— Source evidence: Eight request relationships. Destination check: Eight mapped targets. Decision: Open every link.
Not verified
Eight request relationships
Not verified
Eight mapped targets
Not verified
Open every link
Illustrative fictional migration, not vendor benchmarks. Checked on .

Counts help locate gaps, but equal totals can hide substitution. Compare the actual sets of source IDs, then inspect content and relationships. A comment attached to the wrong request still contributes one to the total. Check all restricted records and unresolved mappings, plus representative ordinary items.

Preserve dates and content without inventing history

Keep original creation, update, and publication dates separate from the migration timestamp. When a destination cannot accept an original date, retain it in a supported historical field or a restricted companion archive, and document the limitation. Do not silently present the import date as the date a customer first raised a problem.

Test rich text, links, images, and downloadable attachments on the destination. An image URL in an export may still point to the old provider. Confirm that assets remain accessible under the intended permissions, and transfer permitted files through a supported path where necessary. Maintain a source-to-destination URL map for redirects or link updates.

Preserve language relationships too. Two translations of one announcement should remain associated where the destination supports that model. If the model differs, record the correspondence explicitly so a later edit does not update only one language by accident.

Make the final switch reversible

Run the first import in a non-public destination with outbound notifications disabled where supported. Check that creating historical requests, changing statuses, or publishing old announcements will not send fresh customer emails. Test visibility using both authorized and unauthorized accounts.

Agree on a final extraction time and how changes after the first export will be collected. That may mean a short, communicated writing freeze or a documented second pass. Include edited and deleted records, not only new ones. Keep the original exports unchanged and store working copies with access limited to the migration team.

Before changing the public entry point, name the person who accepts unresolved exceptions and the condition that would trigger a rollback. Keep the source available long enough to verify destination behavior. If new feedback arrives after the switch, a rollback must account for those new records as well.

Next step: test one connected slice

Choose one request with an author, several voters, a private comment, an attachment, and a linked announcement. Move that slice using your intended method and reconcile every relationship. The result gives you a concrete acceptance test for the full migration, including an honest list of history the destination cannot preserve.

Written by

João Müller