Agent skill

Hubspot Contact Dedup

by jeremylongshore in jeremylongshore/tons-of-skills-marketplace

Deduplicate HubSpot contacts at production scale — surviving import storms, wrong-winner merges, fuzzy-match blind spots, association orphans, rate-limit exhaustion, and silent merge failures on…

MITAuto-check passedSales & Support

Install Hubspot Contact Dedup

skills CLI
$ npx skills add jeremylongshore/tons-of-skills-marketplace --skill hubspot-contact-dedup -a claude-code

Project install by default; add -g for ~/.claude/skills/.

GitHub CLI
$ gh skill install jeremylongshore/tons-of-skills-marketplace hubspot-contact-dedup --agent claude-code

Project scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).

Manual copy
$ git clone --depth 1 https://github.com/jeremylongshore/tons-of-skills-marketplace.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/.curated/hubspot-contact-dedup .claude/skills/hubspot-contact-dedup && rm -rf skills-src

Use ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.

Claude Code skills documentation · loads skills from .claude/skills/

Facts

Skill name
hubspot-contact-dedup
GitHub stars
2.8k
Token cost
~4.3k tokens
SKILL.md length
925 words
Files
3 (incl. references)
Skills in repo
3,342
Repo updated
First seen
Licence
MIT

At a glance

Deduplicate HubSpot contacts at production scale — surviving import storms, wrong-winner merges, fuzzy-match blind spots, association orphans, rate-limit exhaustion, and silent merge failures on…

  • Works in 6 steps: Discover duplicates with search → Select the primary (winner) contact → Normalize emails and phones for fuzzy… → …
  • Cleaning a CRM after a bulk import
  • SKILL.md covers Overview, Auth, Prerequisites and Instructions, plus 4 more sections
  • Calls curl, jq and python3; reaches api.hubapi.com

What it does

Hubspot Contact Dedup is an agent skill from jeremylongshore/tons-of-skills-marketplace. Deduplicate HubSpot contacts at production scale — surviving import storms, wrong-winner merges, fuzzy-match blind spots, association orphans, rate-limit exhaustion, and silent merge failures on conflicting lifecycle or opt-out status. Use when cleaning a CRM after a bulk import, running a nightly dedup pipeline on millions of records, recovering from a merge that destroyed the wrong timeline, or building fuzzy matching beyond HubSpot's native email-uniqueness. Trigger with "hubspot dedup", "hubspot merge…

Its SKILL.md is about 4.3k tokens, which your agent loads only when the skill is triggered. The skill folder holds 3 other files, including reference files (for example `references/API_REFERENCE.md` and `references/implementation-guide.md`). Compatibility notes: Designed for Claude Code

It sits in Sales & Support, covering CRM management. It works with HubSpot. The repository describes itself as: Model-agnostic agent-skills platform with a harness-free canonical layer, verified adapters, and the ccpi package manager. Explore at tonsofskills.com. The licence is MIT.

When your agent uses it

  • Cleaning a CRM after a bulk import
  • Running a nightly dedup pipeline on millions of records
  • Recovering from a merge that destroyed the wrong timeline
  • Building fuzzy matching beyond HubSpots native email-uniqueness

Example prompts

  • “s native email-uniqueness. Trigger with”
  • “hubspot merge contacts”
  • “hubspot duplicate contacts”
  • “/hubspot-contact-dedup”

Requirements

  • Python 3
  • Compatibility (from SKILL.md): Designed for Claude Code
  • Pre-approved tools (allowed-tools): Read, Bash(curl:*), Bash(jq:*), Bash(python3:*)

Workflow steps

6 steps, taken from the step headings in SKILL.md.

  1. Discover duplicates with search
  2. Select the primary (winner) contact
  3. Normalize emails and phones for fuzzy matching
  4. Pre-merge compliance check
  5. Execute merge with rate limiting
  6. Post-merge verification and association repair

What it can do on your machine

Read from SKILL.md and the folder at commit cfae287. It shows what the files ask for, not the result of running them.

  • Tool permissions

    Pre-approves these tools, so the agent can use them without asking each time:

    • Read
    • Bash(curl:*)
    • Bash(jq:*)
    • Bash(python3:*)

    From allowed-tools in the SKILL.md frontmatter.

  • Runs code

    Shell commands in SKILL.md call:

    • curl
    • jq
    • python3

    From the folder's file list and the shell code blocks in SKILL.md.

  • Network

    Hosts in commands or code, which the agent is likely to contact:

    • api.hubapi.com

    Also links to:

    • developers.hubspot.com
    • github.com

    From URLs in SKILL.md, links to its own repository left out.

  • Credentials

    Names no API keys, tokens, secrets or passwords.

    From names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.

  • Compatibility

    Designed for Claude Code

    From compatibility in the SKILL.md frontmatter.

Context cost

Hubspot Contact Dedup loads about 4.3k tokens when it runs, and up to ~16k if it reads all its reference files. Until then it costs about 165 tokens; SKILL.md has 925 words of instructions outside code blocks.

Always · name and description, kept in context so the agent knows when to use it
~165
When it runs · the whole SKILL.md, loaded when a task matches
~4.3k
With references · SKILL.md plus every file in references/, read only if the agent opens them
~16k

Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.

Safety

Auto-check passed

The automated check found no risky patterns in SKILL.md.

Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); files beside SKILL.md are not scanned.

SKILL.md

The full file from jeremylongshore/tons-of-skills-marketplace at commit cfae287, republished under its MIT licence (© jeremylongshore). 925 words, ~4,277 tokens.

Download SKILL.mdSave it as .claude/skills/hubspot-contact-dedup/SKILL.md (or your agent's skills folder). This skill also uses 2 other files; get the full folder from GitHub.
name
hubspot-contact-dedup
description
Deduplicate HubSpot contacts at production scale — surviving import storms, wrong-winner merges, fuzzy-match blind spots, association orphans, rate-limit exhaustion, and silent merge failures on conflicting lifecycle or opt-out status. Use when cleaning a CRM after a bulk import, running a nightly dedup pipeline on millions of records, recovering from a merge that destroyed the wrong timeline, or building fuzzy matching beyond HubSpot's native email-uniqueness. Trigger with "hubspot dedup", "hubspot merge contacts", "hubspot duplicate contacts", "hubspot contact cleanup", "hubspot import duplicates", "hubspot fuzzy match contacts".
allowed-tools
Read, Bash(curl:*), Bash(jq:*), Bash(python3:*)
compatibility
Designed for Claude Code
version
2.9.0
license
MIT
author
Jeremy Longshore <jeremy@intentsolutions.io>
tags
hubspot, crm, deduplication, data-quality

HubSpot Contact Deduplication

Overview

Merge duplicate contacts in HubSpot and operate that process in production, at scale, without data loss. This is not a one-click cleanup guide — it is the logic your pipeline runs when a sales ops team imports 80,000 leads from a tradeshow CSV that already exist in the CRM, when a merge destroys the "winner" contact's email history, when a fuzzy match on "Jon" vs "John" leaves a six-figure deal associated to a ghost record, and when on-call discovers that 40,000 contacts were merged without checking opt-out flags.

The six production failures this skill prevents:

  1. Import storms creating thousands of exact duplicates — HubSpot enforces email uniqueness only at the property level; the merge API has no dedup-all-at-once endpoint. A 100K-row CSV import where 60% of rows already exist creates 60,000 duplicates that must be found and merged one pair at a time within a 100 req/10s rate envelope.
  2. Merge destroying the wrong timeline — POST /crm/v3/objects/contacts/merge requires a primaryObjectId. Picking the wrong one demotes the older contact's full activity timeline — calls, emails, form submissions — to the discarded record's history.
  3. Property-based dedup missing fuzzy matches — Email-exact dedup leaves "john@gmail.com" and "jon.smith@googlemail.com" as separate records. Phone dedup leaves "+1 (512) 867-5309" and "5128675309" as separate records. Without normalization your CRM accumulates a shadow population of semantically identical but technically distinct contacts.
  4. Post-merge association orphans — When a secondary contact has deals, tickets, or company associations, HubSpot re-parents most automatically — but not all. Custom object associations and some third-party-integration links may not follow.
  5. Rate-limit exhaustion on large catalogs — A 1-million-contact dedup scan requires 10,000 batch reads (2.7 hours at full throughput, before merge calls). Naive single-threaded loops exhaust the 500K daily quota before the search phase finishes.
  6. Silent merge failures on conflicting lifecycle or opt-out status — The merge API returns 200 even when the resulting contact has hs_email_optout=true overriding the primary's opted-in status. HubSpot's "most recently updated value wins" rule is wrong for compliance flags.

Auth

Authenticate with a private app token (pat-na1-*) or OAuth access token. Pass it on every request:

bash
Authorization: Bearer {your-token}

Required scopes: crm.objects.contacts.read, crm.objects.contacts.write, crm.associations.read, crm.associations.write. See the hubspot-auth skill for token caching, OAuth refresh, and scope-drift detection.

Prerequisites

  • Python 3.10+ (requests, phonenumbers, rapidfuzz) for the full pipeline
  • HubSpot Professional or Enterprise account (batch merge at scale)
  • Private app token with required scopes (above)
  • jq for shell examples
  • For catalogs >500K contacts: confirm daily quota with HubSpot support

Instructions

Find exact duplicates by email using the search API. Never pull all contacts into memory for comparison — use the search endpoint with specific filter values.

bash
# Find all contacts sharing a normalized email
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts/search" \
  -H "Authorization: Bearer {your-token}" \
  -H "Content-Type: application/json" \
  -d '{
    "filterGroups": [{"filters": [
      {"propertyName":"email","operator":"EQ","value":"jane.doe@example.com"}
    ]}],
    "properties": ["email","firstname","lastname","hs_object_id","createdate",
                   "lifecyclestage","hs_email_optout","hs_email_hard_bounce_reason_enum"],
    "sorts": [{"propertyName":"createdate","direction":"ASCENDING"}],
    "limit": 10
  }' | jq '[.results[] | {id, created:.properties.createdate}]'

For full-portal scans across millions of contacts use the four-stage Python pipeline in implementation-guide.md. The pipeline writes a local SQLite checkpoint so rate-limit interruptions do not require starting over.

Step 2. Select the primary (winner) contact

The oldest contact by createdate is the primary — its timeline is most historically complete. Two overrides apply:

  • If the oldest contact has hs_email_optout=true and the newer one does not, prefer the opted-in record as primary to avoid propagating unsubscribe status.
  • If the oldest contact has a test-domain email (@mailinator.com, @example.com, @test.com), always make the real-address contact the primary.
python
from datetime import datetime

def pick_primary(contacts: list[dict]) -> tuple[dict, list[dict]]:
    """Return (primary, secondaries). contacts is a list of HubSpot result dicts."""
    TEST_DOMAINS = {"mailinator.com","example.com","test.com","yopmail.com"}

    def is_test(email: str) -> bool:
        return (email or "").split("@")[-1].lower() in TEST_DOMAINS

    # Sort oldest first (default primary)
    sorted_c = sorted(contacts, key=lambda c: c["properties"]["createdate"])
    primary = sorted_c[0]

    # Opt-out override
    if primary["properties"].get("hs_email_optout") == "true":
        opted_in = next((c for c in sorted_c[1:] if c["properties"].get("hs_email_optout") != "true"), None)
        if opted_in:
            primary = opted_in

    # Test email override
    if is_test(primary["properties"].get("email", "")):
        real = next((c for c in sorted_c if not is_test(c["properties"].get("email", ""))), None)
        if real:
            primary = real

    secondaries = [c for c in contacts if c["id"] != primary["id"]]
    return primary, secondaries
Step 3. Normalize emails and phones for fuzzy matching

Exact-email dedup leaves a shadow population. Normalize before comparing:

python
import phonenumbers

def normalize_email(raw: str) -> str:
    lower = (raw or "").strip().lower().replace("@googlemail.com", "@gmail.com")
    local, _, domain = lower.partition("@")
    if domain == "gmail.com":
        local = local.split("+")[0].replace(".", "")
    return f"{local}@{domain}" if domain else lower

def normalize_phone(raw: str, region: str = "US") -> str | None:
    try:
        p = phonenumbers.parse((raw or "").strip(), region)
        if phonenumbers.is_valid_number(p):
            return phonenumbers.format_number(p, phonenumbers.PhoneNumberFormat.E164)
    except Exception:
        pass
    return None

For name similarity and the full confidence-scoring matrix, see implementation-guide.md § Stage 2.

Show full SKILL.md (365 more words)Show less
Step 4. Pre-merge compliance check

Before merging, verify neither contact has blocking compliance flags:

python
def pre_merge_check(a: dict, b: dict) -> tuple[bool, str]:
    """Returns (can_merge, reason). False = queue for human review."""
    pa, pb = a["properties"], b["properties"]
    if pa.get("hs_email_hard_bounce_reason_enum") or pb.get("hs_email_hard_bounce_reason_enum"):
        return False, "hard_bounce_present"
    # Asymmetric GDPR legal basis requires human review
    a_gdpr = bool(pa.get("hs_legal_basis"))
    b_gdpr = bool(pb.get("hs_legal_basis"))
    if a_gdpr != b_gdpr:
        return False, "gdpr_basis_asymmetry"
    return True, "ok"

# Expected post-merge opt-out: conservative — opted out if either contact is opted out
def resolve_optout(a: dict, b: dict) -> bool:
    return (a["properties"].get("hs_email_optout") == "true" or
            b["properties"].get("hs_email_optout") == "true")
Step 5. Execute merge with rate limiting
python
import time, requests

MERGE_URL = "https://api.hubapi.com/crm/v3/objects/contacts/merge"
_window_start = time.monotonic()
_window_calls = 0

def rate_gate(burst_limit: int = 90) -> None:
    """Enforce burst limit (90/10s — leaves buffer below HubSpot's 100/10s cap)."""
    global _window_start, _window_calls
    elapsed_ms = (time.monotonic() - _window_start) * 1000
    if elapsed_ms >= 10_000:
        _window_start = time.monotonic()
        _window_calls = 0
    if _window_calls >= burst_limit:
        time.sleep((10_000 - elapsed_ms) / 1000 + 0.05)
        _window_start = time.monotonic()
        _window_calls = 0
    _window_calls += 1

def merge_contacts(token: str, primary_id: str, secondary_id: str) -> bool:
    headers = {"Authorization": f"Bearer {token}", "Content-Type": "application/json"}
    for attempt in range(3):
        rate_gate()
        resp = requests.post(MERGE_URL, headers=headers,
                             json={"primaryObjectId": primary_id, "objectIdToMerge": secondary_id},
                             timeout=30)
        if resp.status_code == 200:
            return True
        if resp.status_code == 429:
            time.sleep(int(resp.headers.get("Retry-After", "10")))
            continue
        if resp.status_code >= 500:
            time.sleep(min(60, 5 * 2 ** attempt))
            continue
        # Non-retryable (400, 404, 409)
        print(f"Merge failed {resp.status_code}: {resp.text}")
        return False
    return False

Stop the pipeline before hitting the daily quota:

python
DAILY_STOP_AT = 480_000  # Stop at 96% of 500K quota

def check_quota(resp: requests.Response) -> None:
    remaining = int(resp.headers.get("X-HubSpot-RateLimit-Daily-Remaining", 500_000))
    if (500_000 - remaining) >= DAILY_STOP_AT:
        raise SystemExit("Daily quota near limit — stopping. Resume after midnight UTC reset.")
Step 6. Post-merge verification and association repair

After merging, verify that the surviving contact's hs_email_optout matches the expected value (Step 4) and patch it if it drifted. Then audit associations that may not have transferred automatically:

bash
# Check associations on surviving contact (replace 12345 with actual primary contact ID)
curl -s "https://api.hubapi.com/crm/v4/objects/contacts/12345/associations/deals" \
  -H "Authorization: Bearer {your-token}" | jq '[.results[].toObjectId]'

# Manually create a missing association (replace 12345 with primary ID, 67890 with deal ID)
curl -s -X PUT \
  "https://api.hubapi.com/crm/v4/objects/contacts/12345/associations/deals/67890" \
  -H "Authorization: Bearer {your-token}" \
  -H "Content-Type: application/json" \
  -d '[{"associationCategory":"HUBSPOT_DEFINED","associationTypeId":3}]'

The full four-stage Python pipeline (scan → pair → qualify → execute) with automatic association repair is in implementation-guide.md.

Error Handling

HTTP StatusErrorRoot CauseAction
400CONTACT_ALREADY_MERGEDSecondary was already merged into another recordRe-fetch secondary; check hs_merged_object_ids for surviving primary ID
400SAME_OBJECT_MERGEBoth IDs are identicalRemove self-merge pairs from candidate list before executing
400INVALID_OBJECT_TYPEOne ID belongs to a different CRM object typeVerify via GET /crm/v3/objects/contacts/{id} before merging
404OBJECT_NOT_FOUNDContact was deleted between discovery and mergeRe-fetch to confirm existence; skip if deleted
409MERGE_IN_PROGRESSA concurrent merge is already running for this contactRetry after 30 seconds
429Rate limitBurst or daily quota exceededHonor Retry-After header; check X-HubSpot-RateLimit-Daily-Remaining
500INTERNAL_ERRORTransient HubSpot platform faultExponential back-off, max 3 retries; log X-HubSpot-Correlation-Id for support
200 (silent)Opt-out propagated incorrectly"Most recently updated wins" resolved compliance flag wrongRun post-merge hs_email_optout verification; patch via PATCH endpoint

Examples

Merge two contacts via curl
bash
# Step 1: find the duplicate pair sorted oldest-first
SEARCH=$(curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts/search" \
  -H "Authorization: Bearer {your-token}" -H "Content-Type: application/json" \
  -d '{"filterGroups":[{"filters":[{"propertyName":"email","operator":"EQ","value":"jane.doe@example.com"}]}],
       "properties":["email","createdate"],"sorts":[{"propertyName":"createdate","direction":"ASCENDING"}],"limit":5}')

PRIMARY_ID=$(echo "$SEARCH" | jq -r '.results[0].id')
SECONDARY_ID=$(echo "$SEARCH" | jq -r '.results[1].id')
echo "primary=$PRIMARY_ID secondary=$SECONDARY_ID"

# Step 2: merge
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts/merge" \
  -H "Authorization: Bearer {your-token}" -H "Content-Type: application/json" \
  -d "{\"primaryObjectId\":\"$PRIMARY_ID\",\"objectIdToMerge\":\"$SECONDARY_ID\"}" \
  | jq '{id, email: .properties.email}'
Dry-run dedup report
bash
python3 - <<'EOF'
import json, subprocess, sys

TOKEN = "{your-token}"
EMAIL = "jane.doe@example.com"

out = subprocess.run([
    "curl","-s","-X","POST","https://api.hubapi.com/crm/v3/objects/contacts/search",
    "-H",f"Authorization: Bearer {TOKEN}","-H","Content-Type: application/json",
    "-d", json.dumps({"filterGroups":[{"filters":[{"propertyName":"email","operator":"EQ","value":EMAIL}]}],
                      "properties":["email","firstname","lastname","createdate","lifecyclestage"],
                      "sorts":[{"propertyName":"createdate","direction":"ASCENDING"}],"limit":10}),
], capture_output=True, text=True).stdout

data = json.loads(out)
contacts = data["results"]
if len(contacts) < 2:
    print("No duplicates found"); sys.exit(0)
print(f"Found {len(contacts)} contacts for {EMAIL}:")
for c in contacts:
    p = c["properties"]
    print(f"  ID {c['id']} | created {p['createdate']} | stage {p.get('lifecyclestage')}")
print(f"\nWould merge: primary={contacts[0]['id']}, secondaries={[c['id'] for c in contacts[1:]]}")
EOF
Batch read to pre-fetch properties before deciding primary
bash
curl -s -X POST "https://api.hubapi.com/crm/v3/objects/contacts/batch/read" \
  -H "Authorization: Bearer {your-token}" -H "Content-Type: application/json" \
  -d '{
    "inputs": [{"id":"101"},{"id":"202"},{"id":"303"}],
    "properties": ["email","phone","firstname","lastname","createdate",
                   "lifecyclestage","hs_email_optout","hs_email_hard_bounce_reason_enum"]
  }' | jq '[.results[] | {id, email:.properties.email, created:.properties.createdate}]'

Output

  • Candidate list grouped by normalized email, phone, or name similarity with confidence scores
  • Winner selection rationale per merge pair (oldest contact, opt-out override, test-email override)
  • Compliance pre-check table per pair (opt-out status, lifecycle, GDPR basis, hard-bounce flag)
  • Association audit report — which transferred automatically and which required manual re-parenting
  • Merge execution log with rate-limit headers and daily quota burn rate
  • Post-merge verification confirming hs_email_optout on surviving records matches expected value
  • Human review queue for pairs flagged with conflicting compliance flags or 0.70–0.84 confidence

Resources

© jeremylongshore, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file

Files

SKILL.md and 2 other files (references) in skills/.curated/hubspot-contact-dedup of jeremylongshore/tons-of-skills-marketplace.

  • SKILL.md
  • references/API_REFERENCE.md
  • references/implementation-guide.md

Open the folder on GitHubat commit cfae287

Compare with similar skills

Hubspot Contact Dedup next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.

Hubspot Contact Dedup compared with similar skills
SkillStarsUsed inTokensAuto-checkLicenceRepo updated
Hubspot Contact Dedup this skilljeremylongshore/tons-of-skills-marketplace2.8k—~4.3kAutomated safety check: PassMIT
Google Maps Exportgmapsscraper/google-maps-agent-skills132—~1.2kAutomated safety check: PassMIT
Lost Deal Revival AgentOthmane-Khadri/YALC-the-GTM-operating-system318—~3kAutomated safety check: PassMIT
HubspotOpenClaudia/openclaudia-skills713—~1.8kAutomated safety check: NotesMIT
Aai Hubspotaai-labs/agent-barn109—~223Automated safety check: PassApache-2.0
Hubspotrefly-ai/refly-skills204—~491Automated safety check: PassNone

Similar skills

  • Google Maps Export

    gmapsscraper/google-maps-agent-skills

    Export Google Maps business data to CSV, JSON, or CRM format (HubSpot, Pipedrive, Salesforce).

    132 GitHub stars~1.2k tokensUpdated 4 mo ago
    Sales & SupportAuto-check passed
  • Lost Deal Revival Agent

    Othmane-Khadri/YALC-the-GTM-operating-system

    Drafts revival messages for closed-lost deals when a public company signal contradicts the original objection.

    318 GitHub stars~3k tokensUpdated 1 mo ago
    Sales & SupportAuto-check passed
  • Hubspot

    OpenClaudia/openclaudia-skills

    Manage HubSpot CRM contacts, companies, deals, and CMS content via API.

    713 GitHub stars~1.8k tokensUpdated 23 days ago
    Sales & SupportAuto-check: notes
  • Aai Hubspot

    aai-labs/agent-barn

    Use aai-cli to inspect HubSpot CRM records, files, events, conversations, visitor identification, and custom channels.

    109 GitHub stars~223 tokensUpdated yesterday
    Sales & SupportAuto-check passed
  • Hubspot

    refly-ai/refly-skills

    Integrate with HubSpot for CRM management. An agent skill from refly-ai/refly-skills.

    204 GitHub stars~491 tokensUpdated 2 mo ago
    Sales & SupportAuto-check passed
  • Hubspot

    Anil-matcha/awesome-muse-connectors

    Read and manage the HubSpot CRM: contacts, contact search, deals.

    1.3k GitHub stars~558 tokensUpdated 5 days ago
    Sales & SupportAuto-check passed

More from jeremylongshore/tons-of-skills-marketplace

All 3,342 skills in this repo
  • Performing Security Code Review

    jeremylongshore/tons-of-skills-marketplace

    Execute this skill enables AI assistant to conduct a security-focused code review using the security-agent plugin.

    2.8k GitHub starsUsed in 2 repos~1.3k tokens
    Auto-check: notes
  • Adapting Transfer Learning Models

    jeremylongshore/tons-of-skills-marketplace

    Build this skill automates the adaptation of pre-trained machine learning models using transfer learning techniques.

    2.8k GitHub stars~1.1k tokensUpdated today
    Auto-check passed
  • Agent Context Loader

    jeremylongshore/tons-of-skills-marketplace

    Execute proactive auto-loading: automatically detects and loads agents.md files.

    2.8k GitHub stars~1.1k tokensUpdated today
    Auto-check passed
  • Aggregating Performance Metrics

    jeremylongshore/tons-of-skills-marketplace

    Aggregate and centralize performance metrics from applications, systems, databases, caches, and services.

    2.8k GitHub stars~1.2k tokensUpdated today
    Auto-check passed
  • Analyzing Capacity Planning

    jeremylongshore/tons-of-skills-marketplace

    Execute this skill enables AI assistant to analyze capacity requirements and plan for future growth.

    2.8k GitHub stars~947 tokensUpdated today
    Auto-check passed
  • Analyzing Database Indexes

    jeremylongshore/tons-of-skills-marketplace

    Process use when you need to work with database indexing. An agent skill from jeremylongshore/tons-of-skills-marketplace.

    2.8k GitHub stars~2k tokensUpdated today
    Auto-check passed

Works with

Categories

Questions about Hubspot Contact Dedup

What does Hubspot Contact Dedup do?

Deduplicate HubSpot contacts at production scale — surviving import storms, wrong-winner merges, fuzzy-match blind spots, association orphans, rate-limit exhaustion, and silent merge failures on…. Hubspot Contact Dedup is an agent skill from jeremylongshore/tons-of-skills-marketplace. Deduplicate HubSpot contacts at production scale — surviving import storms, wrong-winner merges, fuzzy-match blind spots, association orphans, rate-limit exhaustion, and silent merge failures on conflicting lifecycle or opt-out status.

When should I use Hubspot Contact Dedup?

Hubspot Contact Dedup fits situations like: cleaning a CRM after a bulk import; running a nightly dedup pipeline on millions of records; recovering from a merge that destroyed the wrong timeline; building fuzzy matching beyond HubSpots native email-uniqueness.

How do I install Hubspot Contact Dedup in Claude Code?

Run `npx skills add jeremylongshore/tons-of-skills-marketplace --skill hubspot-contact-dedup -a claude-code`. Or copy the skill folder (skills/.curated/hubspot-contact-dedup in jeremylongshore/tons-of-skills-marketplace) into .claude/skills/hubspot-contact-dedup in your project. Claude Code loads it when a task matches its description.

How do I install Hubspot Contact Dedup in Codex?

Run `npx skills add jeremylongshore/tons-of-skills-marketplace --skill hubspot-contact-dedup -a codex`. Or copy the skill folder (skills/.curated/hubspot-contact-dedup in jeremylongshore/tons-of-skills-marketplace) into .agents/skills/hubspot-contact-dedup in your project. Codex loads it when a task matches its description.

Can I use Hubspot Contact Dedup in Cursor, Gemini CLI or GitHub Copilot?

Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add jeremylongshore/tons-of-skills-marketplace --skill hubspot-contact-dedup -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/hubspot-contact-dedup, .gemini/skills/hubspot-contact-dedup, .github/skills/hubspot-contact-dedup and .opencode/skills/hubspot-contact-dedup in your project.

What does Hubspot Contact Dedup need to run?

Going by SKILL.md and its folder, Hubspot Contact Dedup needs the command-line tools its instructions call (curl, jq and python3). Our summary lists: Python 3. Its frontmatter pre-approves these tools: Read, Bash(curl:*), Bash(jq:*), Bash(python3:*). Compatibility (from SKILL.md): Designed for Claude Code.

Does Hubspot Contact Dedup access the network?

SKILL.md names 3 domains. In commands or code: api.hubapi.com; the agent is likely to contact it when it follows the instructions. As links in the text: developers.hubspot.com and github.com. This is read from the text; nothing was executed.

Is Hubspot Contact Dedup safe to install?

Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. Review the folder before installing.

What licence does Hubspot Contact Dedup use?

Hubspot Contact Dedup is published under the MIT licence (declared in SKILL.md). It allows redistribution, so the full SKILL.md is shown on this page.

How many tokens does Hubspot Contact Dedup use?

About 4.3k tokens (SKILL.md is roughly 17k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 12k tokens, read only when the agent opens those files.

What are the alternatives to Hubspot Contact Dedup?

Skills that share tags, products or a category with Hubspot Contact Dedup: Google Maps Export (gmapsscraper/google-maps-agent-skills, 132 stars), Lost Deal Revival Agent (Othmane-Khadri/YALC-the-GTM-operating-system, 318 stars), Hubspot (OpenClaudia/openclaudia-skills, 713 stars) and Aai Hubspot (aai-labs/agent-barn, 109 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.

Who maintains Hubspot Contact Dedup?

jeremylongshore (a GitHub user) maintains it in jeremylongshore/tons-of-skills-marketplace, which has 2,827 GitHub stars. The repository holds 3,342 skills in this directory. The repository was last updated on October 10, 2026.

Source: jeremylongshore/tons-of-skills-marketplace on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.