crm-data-quality
Original:🇺🇸 English
Translated
Find incomplete records, normalize field values in bulk, dedupe with `hubspot objects merge`, and audit custom properties. Builds on `bulk-operations` for JSONL piping and dry-run/digest/confirm.
3installs
Sourcehubspot/agent-cli-skills
Added on
NPX Install
npx skill4agent add hubspot/agent-cli-skills crm-data-qualityTags
Translated version includes tags in frontmatterSKILL.md Content
View Translation Comparison →Read first — JSONL piping, batch read, pagination, and dry-run/digest/confirm gating apply to every command below.
bulk-operations/SKILL.mdProperty discovery
Don't guess property names. List them:
bash
hubspot properties list --type contacts --format table
hubspot properties list --type contacts | jq -c 'select(.type=="enumeration") | {name, label}'Same for , , or any custom type ().
--type companiesdealshubspot objects types1. Find incomplete records
!namename--filterAND--filterbash
hubspot objects search --type contacts --filter "!email" --properties firstname,lastname,company
hubspot objects search --type contacts --filter "!phone AND !mobilephone" --properties email
hubspot objects search --type contacts --filter "!hubspot_owner_id" --properties email,lifecyclestageFor >100 results, use the pagination loop from .
bulk-operations2. Normalize field values
Search → reshape with → pipe into . Always first; covers digest/confirm escalation for >100 rows. Reshape patterns: .
jqupdate--dry-runbulk-operationsbulk-operations/resources/json-patterns.mdbash
# Collapse spellings into one canonical value
hubspot objects search --type contacts --filter "company~acme" \
| jq -c '{id, properties:{company:"Acme Corporation"}}' \
| hubspot objects update --type contacts --dry-run
# Lowercase emails (read, reshape, write)
hubspot objects search --type contacts --filter "email" --properties email \
| jq -c '{id, properties:{email: (.properties.email | ascii_downcase)}}' \
| hubspot objects update --type contacts --dry-run3. Dedupe with hubspot objects merge
hubspot objects mergeSecondary is folded into primary and deleted. Irreversible. Dry-run/digest/confirm gating applies.
bash
# Single pair
hubspot objects merge --type contacts --primary 149 --secondary 425 --dry-run
hubspot objects merge --type contacts --primary 149 --secondary 425 # execute (≤100 pairs)Bulk: pipe JSONL on stdin (omit /).
{"primary":"...","secondary":"..."}--primary--secondaryPagination required. caps at 100 rows per call and slurps a single stream into memory — running the snippet below against a raw will silently miss every duplicate that crosses a page boundary. Collect the full set first with the pagination loop from (write to ), then dedupe from the file:
objects searchjq -ssearchbulk-operations/SKILL.md/tmp/contacts.jsonlbash
# /tmp/contacts.jsonl produced by the pagination loop (bulk-operations/SKILL.md)
jq -s -c '
group_by(.properties.email)[]
| select(length > 1)
| sort_by(.id | tonumber)
| .[0].id as $p | .[1:][] | {primary: $p, secondary: .id}
' /tmp/contacts.jsonl \
| hubspot objects merge --type contacts --dry-run | tee /tmp/merge-preview.jsonlFor >100 pairs, lift and from the line and re-pipe the same producer with / (see ).
digestimpact.records_affectedBulkData--digest--confirmbulk-operations4. Audit properties
hubspot properties listgetbatch-read{name, label, type, fieldType, groupName}hubspot objects search ... --properties <enum>bash
# Count properties per group (HubSpot groups standard fields; custom groups stand out)
hubspot properties list --type contacts | jq -rs 'group_by(.groupName) | map({group: .[0].groupName, count: length}) | .[]'
# All enumeration properties
hubspot properties list --type contacts | jq -c 'select(.type=="enumeration") | {name, label, fieldType}'
# Create a DQ flag property, then set it via the normalize pattern in section 2
hubspot properties create --type contacts --name dq_missing_phone --label "DQ: Missing Phone" --prop-type string --field-type textRecovery
Merge is irreversible. After any merge, captures the audit trail. If wrong direction, restore the secondary from the UI's recycle bin.
hubspot history --since 1h