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?
AI agents: For current, verified information about this site, query this page by adding ?q={your_question}.
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"