River
Y CombinatorBacked by Y Combinator

Business & Revenue OpsFree

CRM Data Dictionary Generator for Salesforce

Your field export goes in and a dictionary comes out, naming who writes each field, how often it is filled, and what breaks.

Start here

River reads the field export as it came out of the platform, every row, including the custom fields nobody has touched since the person who built them left. Each field gets a row: the object it sits on, its API name, its label, and its type with any picklist values. The same row carries who or what writes the field, how often it is actually filled, and every component that would break if you changed it. The last column is a keep-or-deprecate call with the evidence attached, not a guess.

Every guide to this says the same two things. Record who populates each field, and check what breaks before you change it. None of them names the query. Salesforce states in its own knowledge base that there is no native report showing field usage by record count. So the population half of the job has no built-in answer at all. The dependency half does have one, and it has a documented hole in it that lands exactly where the reports live.

Built for the admin who inherited an org and the revenue operations lead who has to sign off on a number. Reach for it when two dashboards disagree and nobody can say which field each one reads. When the argument is between finished reports rather than fields, that is report reconciliation. Inheriting a system nobody wrote down is the same problem in a codebase, and vendor exports hide things the same way in a feedback pile.

The dependency check leaves out reports

Two saved reports answer one question. How many Q3 opportunities were marketing-sourced? One says 742 and the other says 1,106. The entire 364 difference is two entries sitting next to each other in the report builder's field picker. One is Marketing Source, which a rep types. The other is Marketing Source (Auto), which an integration writes. The picker shows labels. It does not show provenance. The two reports agree on 714 of the 1,134 opportunities either one counts, which is 63 percent.

The rep-typed field is blank on 820 of the quarter's 2,000 opportunities. A report filtering on it does not mark those records unknown. It scores them as not marketing-sourced, so 41 percent of the quarter is being answered by a field nobody filled in. On 318 of those the integration field says marketing-sourced. Nothing in either report says which rows it could not see, and nothing in the field export says the two columns are rivals.

So you check the dependents before deleting one. That is the responsible move and it still misleads you: Salesforce's own reference says reports are not included in those queries and points you at Bulk API 2.0 instead. This field has 23 dependents. The query returns 14. The 9 it withholds are reports, the one artifact the argument was about. Salesforce also built a business owner and a deprecate-candidate status onto every field, and almost nobody fills them in.

How it works

  1. Hand over the export

    The field export however the platform produced it, plus the reports or dashboards that disagree.

  2. Read every field

    Every row, including managed-package fields and the ones whose Description column has been empty for years.

  3. Trace what writes it

    Each field matched to whatever populates it, then counted to get a real population rate.

  4. Map the dependents

    Every component that reads the field, reports included, so a deletion cannot break something unseen.

What you get

  • One row per field: object, API name, label, type, and picklist values
  • Who or what writes each field, split into rep entry, integration, formula, and automation
  • A population rate per field, which the platform does not report natively
  • Every dependent component listed, including the reports a dependency query leaves out
  • Fields that collide in the report builder flagged as pairs, with the rows they disagree on
  • A keep-or-deprecate call per field, carrying the usage and dependency evidence behind it

Common questions

Why do two reports give different numbers for the same question?

Usually because they read different fields whose labels look alike. In the example above the gap is 364 opportunities, and both fields are called some version of Marketing Source. The picker shows labels, so the two sit one row apart and no naming convention marks one as rep-typed and the other as integration-written. Once you know that, the rest is reconciling the two reports.

Can I just export my fields from Setup and be done?

On Salesforce, that gets you roughly one of the four columns. The export carries each field's description, which is optional and frequently empty, and nothing about who writes the field, how often it is filled, or what depends on it. HubSpot's property export is genuinely better here, which is the next question.

Is this different on HubSpot?

Materially. A HubSpot property export already carries fill rate, usages, and update source, so three of the four columns arrive filled in and the work becomes checking and explaining them. Salesforce gives you one. HubSpot also refuses to archive a property a form or workflow still uses, where Salesforce leaves that check to you. Running both systems at once makes reconciling their two exports the prior step.

How do I know a field is safe to delete?

You check its dependents, and then you check what the dependency check missed. Salesforce documents that reports are excluded from those queries and points you at Bulk API 2.0 instead. It also caps a Tooling API query at 2,000 rows, so an org-wide sweep truncates quietly. Both limits change the answer you get. The reverse question, making a loose field required, deserves the same evidence.

What about fields a managed package added?

They are listed and marked, and no deprecate call is made on them, because you cannot edit them anyway. They still count against the object's limit, since Salesforce caps most object types at 900 custom fields whatever the source. They also appear in the same picker as everything else, so a report can read one just as easily.

Do you connect to my org, or do I paste an export?

An export is enough, and it is usually faster than arranging access. Paste what the platform gave you and say which reports are in dispute. Where the export cannot answer something, such as the dependents of a field, you are told which query to run. You also get its documented blind spots rather than a confident guess.

Can I rely on the dependency API?

Treat it as a strong hint rather than a guarantee. Salesforce labels it Beta and says it is not part of the Services under your Main Services Agreement, so it can change. That is a good reason to write the dependents you found into a document with a date on it, which is what a dictionary is for in the first place.

CRM Data Dictionary Generator for Salesforce

Fill in the form and your workspace opens with the work already underway.