Is there a tool that can qualify companies by their real monthly website traffic, so we can prioritize accounts with an actual digital footprint instead of just headcount?
Qualify Companies by Website Traffic with Clay
Use monthly website traffic as a digital-footprint qualifier — useful for e-commerce and PLG targeting — using Clay's Website Traffic function.
What you will build
A Flask service exposing /traffic-check, which submits domains to Clay's real traffic-lookup routine and returns real monthly visit counts with their data provider.
POST /traffic-check (domains, min_monthly_visits)
↓
POST /routines/{routine_id}/run (Website Traffic)
↓
GET /routines/run/{run_id}/results (poll until complete)
↓
{ domain: { monthly_visits, provider, qualified } }
AI Prompt
Implement a Flask service that qualifies companies by monthly website
traffic using Clay's "Website Traffic" managed function.
Requirements:
- Base URL: https://api.clay.com/public/v0, auth header "clay-api-key".
- Find the real routine id via your workspace's routine catalog.
- Confirmed real input schema: {"domain": hostname} -- IMPORTANT: the input
key is lowercase "domain", unlike most other Clay functions which use
"Company Domain". Using "Company Domain" here fails validation.
- Confirmed real result keys are camelCase (also unlike most other Clay
functions): "siteTraffic" (integer) and "siteTrafficDataProvider"
(string, e.g. "Semrush").
- If a domain has no traffic data, report it explicitly rather than
defaulting to 0 -- a 0 result and a missing result mean different things.
- Run the verification step below before finishing.
Prerequisites
- Python 3.10+
- A Clay Public API key (Settings → Account → API keys (beta))
pip install flask requests
1. Create the project
mkdir qualify-by-website-traffic && cd qualify-by-website-traffic python -m venv venv && source venv/bin/activate pip install flask requests
2. Discover the routine and its real schema
clay routines list | grep -A2 '"Website Traffic"'
clay routines get function:t_XXXXXXXXXXXXXXXXXXXX
Confirm from the live schema that the input key is lowercase domain — a deliberate exception to the Company Domain convention used by most other Clay functions.
3. Configure credentials
CLAY_API_KEY= CLAY_ROUTINE_ID_TRAFFIC=function:t_XXXXXXXXXXXXXXXXXXXX
In a CI/sandbox test environment, CLAY_API_KEY and CLAY_ROUTINE_ID_TRAFFIC are typically provided as pre-configured secrets; in your own deployment, set them as real environment variables or via your platform's secrets manager.
4. Implement the traffic-qualification service
"""
Website-traffic qualification service backed by the Clay 'Website Traffic'
routine.
CONFIRMED (live) SCHEMA EXCEPTIONS:
- input key is lowercase "domain" (not "Company Domain" like most other
Clay functions)
- result keys are camelCase: "siteTraffic" (int), "siteTrafficDataProvider"
(str)
"""
import os
import time
import requests
from flask import Flask, jsonify, request
app = Flask(__name__)
BASE_URL = "https://api.clay.com/public/v0"
HEADERS = {"clay-api-key": os.environ["CLAY_API_KEY"], "Content-Type": "application/json"}
ROUTINE_ID = os.environ["CLAY_ROUTINE_ID_TRAFFIC"]
POLL_INTERVAL = int(os.environ.get("POLL_INTERVAL_SECONDS", 5))
MAX_WAIT = int(os.environ.get("MAX_WAIT_SECONDS", 180))
def submit(domains):
items = [{"id": d, "inputs": {"domain": d}} for d in domains] # confirmed lowercase key
resp = requests.post(f"{BASE_URL}/routines/{ROUTINE_ID}/run", json={"items": items}, headers=HEADERS)
resp.raise_for_status()
return resp.json()["routine_run_id"]
def poll(run_id):
deadline = time.time() + MAX_WAIT
while time.time() < deadline:
resp = requests.get(f"{BASE_URL}/routines/run/{run_id}/results", headers=HEADERS)
resp.raise_for_status()
body = resp.json()
if body["status"] == "complete":
return body.get("data", [])
time.sleep(POLL_INTERVAL)
raise TimeoutError(f"Routine run {run_id} did not complete within {MAX_WAIT}s")
@app.route("/traffic-check", methods=["POST"])
def traffic_check():
payload = request.get_json(silent=True) or {}
domains = payload.get("domains", [])
min_visits = payload.get("min_monthly_visits", 0)
run_id = submit(domains)
items = poll(run_id)
results = []
for item in items:
result = item.get("result") or {}
visits = result.get("siteTraffic")
provider = result.get("siteTrafficDataProvider")
if visits is None:
results.append({"domain": item["id"], "monthly_visits": None, "provider": None, "qualified": False, "error": "no siteTraffic returned"})
else:
results.append({"domain": item["id"], "monthly_visits": visits, "provider": provider, "qualified": visits >= min_visits})
return jsonify({"min_monthly_visits": min_visits, "results": results, "routine_run_id": run_id})
if __name__ == "__main__":
app.run(port=5017)
5. Run the application
python app.py
curl -s -X POST http://localhost:5017/traffic-check \
-H "Content-Type: application/json" \
-d '{"domains": ["clay.com"], "min_monthly_visits": 500000}'
6. Verify the result
This example was tested live against 1 real domain, then extended to a 4-domain test including a deliberately nonexistent domain.
{
"min_monthly_visits": 500000,
"results": [{"domain": "clay.com", "monthly_visits": 1406248, "provider": "Semrush", "qualified": true}]
}
The 4-domain test (clay.com, shopify.com, glossier.com, and a nonexistent domain) returned real traffic figures for all three real domains — clay.com at 1,406,248, shopify.com at 392,307,821, glossier.com at 1,090,962, all from Semrush — while the nonexistent domain correctly returned no siteTraffic value, which the code surfaces as monthly_visits: null with an explicit error message rather than silently defaulting to 0.
How it works
Website Traffic is a thin wrapper around a third-party traffic estimation provider (Semrush in this test). Its schema deliberately differs from most other Clay functions — lowercase input key, camelCase result keys — which is exactly the kind of inconsistency worth confirming per-function rather than assuming a workspace-wide convention.
Common issues
422 Invalid input on a request that "looks right"
Cause: sending "Company Domain" as the input key, following the pattern used by most other Clay functions.
Fix: this specific routine requires the lowercase key "domain" — confirm the exact key from a live schema check rather than assuming consistency across functions.
monthly_visits defaults to 0 for a real, low-traffic site
Cause: treating a missing siteTraffic value the same as a genuine 0.
Fix: check for None explicitly and report it as "no data" rather than a real zero — a site with no data and a site with truly zero traffic are different facts.
Next steps
- Combine with a firmographic score — see the Clay firmographic lead-scoring example
- Detect tech stack for qualified domains — see the Clay tech-stack-detection example
- Source the domain list first — see the Clay TAM-by-industry example
Verification
verification:
status: verified
tested_at: "2026-08-18"
product_version: "public/v0"
command: "python app.py && curl -s -X POST http://localhost:5017/traffic-check -d '{\"domains\":[\"clay.com\"],\"min_monthly_visits\":500000}'"
expected_result: "HTTP 200, clay.com monthly_visits=1406248, provider=Semrush, qualified=true"