Skip to content

Every 15 minutes

Check new HubSpot contacts and companies for bad data

New contacts with broken emails and new companies with dead websites are flagged in Slack before anyone works them.

Runs
Every 15 minutes
Apps
HubSpot, Slack
AI
Not needed
Access
HubSpot crm.objects.contacts.read/write, crm.objects.companies.read/write; Slack chat:write

Send this to your assistant

Create a ClickRuntime automation: every 15 minutes, check new HubSpot companies and contacts. If a company website doesn't load or a contact email looks invalid, mark the record and post it in #crm.

Paste it into your assistant. It tells you what it will send or change before it runs live.

First time? Adding ClickRuntime to your assistant takes about two minutes.

Why use it

Why teams use this automation

A marketing team imports leads from events, forms and partner lists into HubSpot. A good share arrive with typos in email addresses or company websites that no longer exist. Reps discover this one at a time, after a bounced email or a wasted research session.

This automation checks each new contact and company soon after it is created, marks the ones that fail, and posts them in Slack so someone can fix or remove them while the source is still fresh.

What you get out of it

  • Fewer bounced emails

    Catching malformed addresses before the first sequence goes out protects your sending reputation and keeps open rates honest.

  • Reps spend time on real companies

    A company whose website does not load is often closed, renamed or a typo. Flagging it saves a rep from researching a dead end.

  • Problems are fixed at the source

    Seeing bad records within minutes of import makes it easy to trace them back to the form or list that produced them.

  • A cleaner CRM over time

    Every record is checked once when it arrives, so data quality improves steadily instead of needing a big clean-up every quarter.

How it works

What happens, step by step

  1. Every 15 minutes ClickRuntime looks for contacts and companies created in HubSpot since the last check.

  2. It checks that each contact's email address is well formed and that each company's website loads.

  3. Records that fail are marked in HubSpot so they are easy to filter.

  4. A list of the failed records is posted in your #crm Slack channel. Records already checked are never checked again.

Before it runs live

  • Connect HubSpot
  • Connect Slack, then invite the app to the channel (type /invite @ClickRuntime there)

What you get

RunsEvery 15 minutes
Check new HubSpot contacts and companies for bad datatoday, 9:00Succeeded
Slack · #crmData check failed: • email jane@northwind,com • Acme Logistics website (acmelogistics.example does not load)

Build your own

Need it to work differently?

This template is a starting point. Copy the prompt and change it, or describe a different automation from scratch, with your own conditions, more apps or an AI step. Your assistant writes it, tests it and runs it on ClickRuntime.
  • Your own rules

    Conditions, thresholds, filters and exceptions, written the way you'd explain them to a colleague.

  • Any number of apps

    One automation can read from one app and update several others. Over 248 apps are ready, and anything with an API works too.

  • AI where it helps

    Summaries, classification, extraction and drafts use ClickRuntime's built-in AI, with no extra key.

  • On a schedule or on each event

    Runs as often as every 5 minutes, or the moment an app sends an event, and keeps track of what it already handled.

Changes you can ask for

  • Act only on the items that match your own rules, and skip the rest
  • Add an AI step, for example to summarize, sort or draft a reply
  • Add another app, for example also send it to Google Sheets
  • Combine it with other HubSpot and Slack steps into one automation

Under the hood

The code that runs this automation

This is the Python script that runs each time the automation starts. Your AI assistant writes it for you when you send the prompt, and you allow each step in your assistant. To change how the automation works, describe the change to your assistant and it updates the script for you. For every function it can use, see the script reference.
data_checks_on_new_hubspot_contacts_and_companies.pyexample
import re
from clickruntime import on_trigger, credentials, http, notify, state, report_fetched
API = "https://api.hubapi.com/crm/v3/objects"
@on_trigger
def run(event):
    h = {"Authorization": f"Bearer {credentials.secret('HUBSPOT_API_KEY')}"}
    since = state.get("since") or "2026-01-01T00:00:00Z"
    body = lambda props: {"filterGroups": [{"filters": [{"propertyName": "createdate", "operator": "GT", "value": since}]}],
                          "properties": props, "sorts": [{"propertyName": "createdate", "direction": "ASCENDING"}], "limit": 100}
    contacts = http.post(f"{API}/contacts/search", headers=h, json=body(["email", "createdate"])).json()["results"]
    companies = http.post(f"{API}/companies/search", headers=h, json=body(["name", "domain", "createdate"])).json()["results"]
    report_fetched(len(contacts) + len(companies))
    if not contacts and not companies:
        return {"checked": 0}
    bad = []
    for c in contacts:
        if not re.fullmatch(r"[^@\s]+@[^@\s]+\.[a-z]{2,}", (c["properties"].get("email") or "").lower()):
            bad.append(("contacts", c["id"], f"email {c['properties'].get('email')}"))
    for c in companies:
        try:
            ok = http.get(f"https://{c['properties'].get('domain')}", timeout=10).status_code < 400
        except Exception:
            ok = False
        if not ok:
            bad.append(("companies", c["id"], f"{c['properties'].get('name')} website"))
    for kind, rid, _ in bad:
        http.patch(f"{API}/{kind}/{rid}", headers=h, json={"properties": {"data_check": "failed"}})
    if bad:
        notify.slack("Data check failed:\n" + "\n".join(f"• {why}" for _, _, why in bad), channel="#crm")
    state.set("since", max(r["properties"]["createdate"] for r in contacts + companies))
    return {"checked": len(contacts) + len(companies), "flagged": len(bad)}

FAQ

Common questions

What makes an email look invalid?
Missing @ signs, spaces, impossible domains and obvious typos such as gmial.com. It checks the format and that the domain exists, not whether the mailbox is in use.
Does it delete bad records?
No. It sets a property on the record, such as Data check failed, so you can filter, fix or remove them yourself.
Are existing records checked too?
Only records created after it starts. Older records can be checked by running it once over a date range you choose.
What permissions does it need?
HubSpot crm.objects.contacts.read/write, crm.objects.companies.read/write; Slack chat:write. Nothing else in your accounts is used.
Does it need AI?
No. It runs without AI, so it doesn't use your plan's AI allowance.
How many runs does it use?
One run each time it checks. Checks that find nothing new and stop right away aren't counted.
Can I change how it works?
Yes. Describe the change to your AI assistant, for example a different schedule, channel or filter. It updates the automation, tests it and tells you what changed.

Set up “Check new HubSpot contacts and companies for bad data” from your assistant

Copy the prompt above, or connect your assistant first. Free plan, no credit card.