Track Competitor Launches in Real Time with You.com Web Search API, One, HubSpot, and Slack


LI Test
URL CopiedLI Test
TLDR: Competitive intelligence workflows that rely on manual monitoring miss product launches for days or weeks. The You.com Web Search API enables AI agents to query a live, continuously updated news index programmatically, returning structured JSON results that can be filtered, enriched with CRM context from HubSpot, and routed as formatted alerts to Slack without requiring a human in the loop. This article describes a production-ready daily agent loop that does exactly that, built on withone.ai, the AI agent infrastructure platform that handles authentication, request building, and execution across all three APIs through a single CLI.
What Does This Competitive Intelligence Stack Do?
The agent loop performs four discrete steps on a daily schedule, all orchestrated through the One CLI:
- Search: The You.com Web Search API queries for product launch news from a defined list of competitor names. Queries use the
queryparameter with structured terms like "[Competitor] new product launch OR feature release", scoped to recent results using the freshness parameter (supported values:day,week,month,year). - Filter: Results are scored for significance. Articles from low-signal sources (press release aggregators, content farms) are excluded. Results already seen in previous runs are deduplicated by URL hash.
- Enrich: The competitor name is cross-referenced against HubSpot CRM using their Search API to determine whether the competitor is an active deal, a closed-lost account, or not in the pipeline at all.
- Alert: A formatted Slack message is posted to
#competitive-intelvia the Slack Web API, including the article title, source, summary snippet, and the CRM context label (In pipeline,Closed lost, orNot in CRM).
One CLI handles OAuth authentication, request construction, and response parsing for all three platforms. This removes the need for API keys in environment variables, SDK installations, and token refresh logic.
Prerequisites: Connecting Platforms with One CLI
Before running the loop, connect You.com, HubSpot, and Slack to your One CLI account. Each connection is a one-time OAuth flow that opens in your browser:
one add you # You.com Search API
one add hubspot # HubSpot CRM
one add slack # Slack workspaceAfter connecting, verify all three platforms are operational:
one --agent connection list{
"total": 3,
"connections": [
{"platform": "you", "state": "operational", "key": "live::you::default::a1b2c3..."},
{"platform": "hubspot", "state": "operational", "key": "live::hubspot::default::d4e5f6..."},
{"platform": "slack", "state": "operational", "key": "live::slack::default::g7h8i9..."}
]
}How Does the You.com Web Search API Enable This Workflow?
The You.com Web Search API returns unified search results from both web and news sources as structured JSON, without requiring HTML scraping or third-party parsing libraries. Each result object includes title, url, description, snippets (an array of text excerpts), and page_age fields, which map directly to the data an alert needs to be useful.
Finding the Right Action
One CLI follows a three-step workflow: search for the right action, read its knowledge (parameter schema), then execute. First, search for the You.com search action:
one --agent actions search you "web search" -t executeThis returns available actions with their IDs. The key action is "Search Unified Web and News Results" (GET /v1/search). Before executing, read the action's knowledge to understand the required parameters:
one --agent actions knowledge you <actionId>Executing a Search
The search action is a GET request with query as a required query parameter and several optional filters:
one --agent actions execute you <actionId> <you_connection_key> \
--query-params '{
"query": "Acme Corp product launch OR new feature OR release",
"count": 10,
"freshness": "week",
"livecrawl": "all"
}'| Parameter | Type | Description |
|---|---|---|
query | string | Required. The search query to execute. |
count | integer | Number of results to return. |
freshness | string | Filter by recency: day, week, month, year. |
livecrawl | string | Source selection: web, news, or all. |
country | string | Country code filter (e.g., US, GB, IN). |
language | string | Language code filter (e.g., EN, FR, DE). |
include_domains | string | Comma-separated allowlist of domains to restrict results to. |
exclude_domains | string | Comma-separated list of domains to exclude from results. |
boost_domains | string | Comma-separated list of domains to boost in ranking. |
The response is structured JSON with results grouped by type:
{
"results": {
"web": [
{
"url": "https://techcrunch.com/2026/06/15/acme-corp-launches-ai-suite",
"title": "Acme Corp Launches Enterprise AI Suite",
"description": "Acme Corp announced a new enterprise AI platform...",
"snippets": ["The suite includes natural language processing..."],
"page_age": "2 days ago",
"authors": ["Jane Reporter"],
"favicon_url": "https://techcrunch.com/favicon.ico"
}
],
"news": [
{
"title": "Acme Corp Announces Enterprise AI Platform",
"description": "The new platform targets Fortune 500 customers...",
"page_age": "2026-06-15T08:30:00Z",
"url": "https://news.example.com/acme-ai-launch"
}
]
},
"metadata": {
"search_uuid": "8d7f4d8e-2f4d-4f8f-9f2d-123456789abc",
"query": "Acme Corp product launch OR new feature OR release",
"latency": 0.482
}
}For a competitive monitoring loop, you iterate over results.web and results.news, apply a significance filter (keyword matching against the description and title fields), and pass qualifying items downstream to HubSpot enrichment. Using livecrawl: "all" ensures you catch both web articles and news wire coverage in a single call.
How Do I Filter Results for Signal vs. Noise?
Raw search results for competitor names contain a high proportion of low-signal content—think listicles, job postings, analyst roundups, and republished press releases. A lightweight filter function reduces false positives before any CRM or Slack call is made.
A practical signal filter checks three conditions:
HIGH_SIGNAL_KEYWORDS = [
"launch", "announce", "release", "new feature",
"integrates", "partnership", "acquires", "raises"
]
NOISE_DOMAINS = ["prnewswire.com", "businesswire.com", "globenewswire.com"]
def is_high_signal(result: dict) -> bool:
text = (result.get("title", "") + " " + result.get("description", "")).lower()
has_signal_keyword = any(kw in text for kw in HIGH_SIGNAL_KEYWORDS)
is_noise_source = any(nd in result.get("url", "") for nd in NOISE_DOMAINS)
return has_signal_keyword and not is_noise_sourceDeduplication across daily runs uses a persistent URL hash store (Redis or a local SQLite table). If result["url"] is already in the seen set, skip it. This prevents the same launch from triggering multiple Slack alerts across consecutive days.
How Do I Cross-Reference Competitors in HubSpot CRM?
HubSpot's CRM API allows you to search for a company by name and return its properties. This adds pipeline context to every alert—the difference between "a competitor you've never tracked" and "a competitor you lost a deal to three months ago" is operationally significant.
Finding the Right Action
one --agent actions search hubspot "search companies by object type" -t executeThis returns the "Search CRM Objects (Companies) by Object Type" action (POST /crm/objects/2026-03/{objectType}/search). Read its knowledge for the full parameter schema:
one --agent actions knowledge hubspot <actionId>Executing a Company Search
The action requires objectType as a path variable and a JSON body with filter groups, properties, and paging parameters:
one --agent actions execute hubspot <actionId> <hubspot_connection_key> \
--path-vars '{"objectType": "companies"}' \
-d '{
"after": "0",
"filterGroups": [{
"filters": [{
"propertyName": "name",
"operator": "CONTAINS_TOKEN",
"value": "Acme Corp"
}]
}],
"limit": 1,
"properties": ["name", "lifecyclestage", "hs_lastmodifieddate"],
"sorts": []
}'The response includes matching companies with their properties:
{
"total": 1,
"results": [
{
"id": "12345",
"properties": {
"name": "Acme Corp",
"lifecyclestage": "opportunity",
"hs_lastmodifieddate": "1718467200000"
},
"createdAt": "2024-01-10T09:00:00Z",
"updatedAt": "2026-06-15T12:00:00Z"
}
]
}The returned lifecycle stage is appended to the Slack message payload, giving the recipient immediate orientation on competitive exposure. If total is 0, the competitor is labeled "Not in CRM".
How Do I Post Structured Alerts to Slack?
The Slack Web API chat.postMessage endpoint accepts a blocks array for rich formatting. A well-structured competitive intelligence alert includes the competitor name as the header, the article title as a link, the snippet as body text, and the CRM status as a labeled context block.
Finding the Right Action
one --agent actions search slack "post message" -t executeThis returns the "Send a Message to a Channel (chat.postMessage)" action. Read its knowledge:
one --agent actions knowledge slack <actionId>Executing a Slack Post
The action is a POST with channel as a required body field and blocks for rich formatting:
one --agent actions execute slack <actionId> <slack_connection_key> \
-d '{
"channel": "#competitive-intel",
"text": "Competitor Signal: Acme Corp — Acme Corp Launches Enterprise AI Suite",
"blocks": [
{
"type": "header",
"text": {"type": "plain_text", "text": "Competitor Signal: Acme Corp"}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*<https://techcrunch.com/2026/06/15/acme-corp-launches-ai-suite|Acme Corp Launches Enterprise AI Suite>*\nAcme Corp announced a new enterprise AI platform targeting Fortune 500 customers..."
}
},
{
"type": "context",
"elements": [
{"type": "mrkdwn", "text": "CRM Status: *In CRM — stage: opportunity*"},
{"type": "mrkdwn", "text": "Source: techcrunch.com"}
]
}
]
}'Note: Slack uses its own mrkdwn syntax, not standard Markdown. Use *bold* (single asterisks) and <url|link text> (angle brackets with pipe) instead of **bold** and [link](url).
Post to #competitive-intel once per qualifying result. Slack allows approximately 1 message per second per channel, with additional workspace-level burst limits. Rate-limit your loop to avoid burst throttling on days with multiple launches.
What Does the Full Agent Loop Look Like?
The complete daily loop combines all four steps into a single orchestrator script. Each step calls the One CLI, which handles authentication and request execution. No API keys are stored in the script itself, One CLI manages credentials through its connection system.
import json
import subprocess
import sqlite3
import os
COMPETITORS = ["Acme Corp", "Rival Inc", "Contender AI"] # replace with your list
SLACK_CHANNEL = "#competitive-intel"
# Connection keys from `one --agent connection list`, read from env vars
YOU_CONN = os.environ["YOU_CONN"]
HUBSPOT_CONN = os.environ["HUBSPOT_CONN"]
SLACK_CONN = os.environ["SLACK_CONN"]
# Action IDs from `one --agent actions search`
YOU_SEARCH_ACTION = "conn_mod_def::GK9ryAH-nnE::w01ioTnIQNe0B_qm2YtVnQ"
HUBSPOT_SEARCH_ACTION = "conn_mod_def::GJ3kQvNreBM::Zpab8Ig5TSivqCj1UhG37w"
SLACK_POST_ACTION = "conn_mod_def::GJ7H84zBlaI::BCfuA16aTaGVIax5magsLA"
def one_execute(platform, action_id, conn_key, path_vars=None, query_params=None, data=None):
cmd = ["one", "--agent", "actions", "execute", platform, action_id, conn_key]
if path_vars:
cmd += ["--path-vars", json.dumps(path_vars)]
if query_params:
cmd += ["--query-params", json.dumps(query_params)]
if data:
cmd += ["-d", json.dumps(data)]
result = subprocess.run(cmd, capture_output=True, text=True)
if result.returncode != 0:
raise RuntimeError(f"One CLI failed: {result.stderr}")
return json.loads(result.stdout)
def get_seen_urls(db_path="seen_urls.db") -> set:
conn = sqlite3.connect(db_path)
conn.execute("CREATE TABLE IF NOT EXISTS seen (url TEXT PRIMARY KEY)")
urls = {row[0] for row in conn.execute("SELECT url FROM seen")}
conn.close()
return urls
def mark_seen(url: str, db_path="seen_urls.db"):
conn = sqlite3.connect(db_path)
conn.execute("INSERT OR IGNORE INTO seen VALUES (?)", (url,))
conn.commit()
conn.close()
def get_crm_context(competitor_name: str) -> str:
response = one_execute(
"hubspot", HUBSPOT_SEARCH_ACTION, HUBSPOT_CONN,
path_vars={"objectType": "companies"},
data={
"after": "0",
"filterGroups": [{
"filters": [{
"propertyName": "name",
"operator": "CONTAINS_TOKEN",
"value": competitor_name
}]
}],
"limit": 1,
"properties": ["name", "lifecyclestage"],
"sorts": []
}
)
if response.get("total", 0) == 0:
return "Not in CRM"
company = response["results"][0]
stage = company["properties"].get("lifecyclestage", "unknown")
return f"In CRM — stage: {stage}"
def post_to_slack(channel: str, competitor: str, result: dict, crm_context: str):
title = result.get("title", "Untitled")
url = result.get("url", "")
description = result.get("description", "")
source = url.split("/")[2] if "/" in url else "unknown"
one_execute(
"slack", SLACK_POST_ACTION, SLACK_CONN,
data={
"channel": channel,
"text": f"Competitor Signal: {competitor} — {title}",
"blocks": [
{
"type": "header",
"text": {"type": "plain_text", "text": f"Competitor Signal: {competitor}"}
},
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": f"*<{url}|{title}>*\n{description}"
}
},
{
"type": "context",
"elements": [
{"type": "mrkdwn", "text": f"CRM Status: *{crm_context}*"},
{"type": "mrkdwn", "text": f"Source: {source}"}
]
}
]
}
)
def run_competitive_intel_loop():
seen_urls = get_seen_urls()
for competitor in COMPETITORS:
response = one_execute(
"you", YOU_SEARCH_ACTION, YOU_CONN,
query_params={
"query": f"{competitor} product launch OR new feature OR release",
"count": 10,
"freshness": "week",
"livecrawl": "all"
}
)
results = response.get("results", {})
all_results = results.get("web", []) + results.get("news", [])
for result in all_results:
url = result.get("url", "")
if url in seen_urls:
continue
if not is_high_signal(result):
continue
crm_context = get_crm_context(competitor)
post_to_slack(SLACK_CHANNEL, competitor, result, crm_context)
mark_seen(url)
# Schedule via cron: 0 8 * * * python run_competitive_intel_loop.pyThis runs once per day, deduplicates across runs, and posts only net-new high-signal results with CRM enrichment attached. The One CLI handles all authentication transparently—if a token expires, One refreshes it automatically on the next call.
How Does This Compare to Manual Competitive Tracking?
| Capability | Manual Tracking | This stack (You.com + One + HubSpot + Slack) |
|---|---|---|
| Detection lag | 1–5 days | Same day (daily cron) or near-real-time (hourly) |
| CRM enrichment | Manual lookup | Automated via One CLI + HubSpot Companies API |
| Alert format | Email forward or Slack paste | Structured Block Kit with source, snippet, CRM label |
| Deduplication | None (re-alerts common) | URL-hash store across runs |
| Coverage | Depends on analyst bandwidth | Scales to any number of tracked competitors |
| Auth management | API keys in env vars, token refresh code | One CLI handles OAuth for all platforms |
| Integration effort | SDK installs + auth code per platform | one add <platform> + ~80 lines of Python |
Get Started
- Install One CLI and connect your platforms:
one init --auth browser
one add you
one add hubspot
one add slack- Find your action IDs by searching each platform:
one --agent actions search you "web search" -t execute
one --agent actions search hubspot "search companies by object type" -t execute
one --agent actions search slack "post message" -t execute- Copy the full orchestrator script from above, replace the connection keys and action IDs with your own (from
one --agent connection list), and schedule it via cron or GitHub Actions.
The You.com Web Search API is available on a free tier with no credit card required. Full API documentation is at you.com/docs. For enterprise rate limits and SLA, contact the You.com team directly.
Built on withone.ai—AI agent infrastructure for competitive and GTM workflows.
Frequently Asked Questions
The You.com Web Search API returns unified results from both web and news sources, controlled by the livecrawl parameter (web, news, or all). Each result includes a page_age field that can be used to filter for recent content. For news-specific retrieval, set livecrawl: "news" or structure your query to include publication-intent signals (e.g., "announces", "launches", "releases") and combine with freshness: "day" or freshness: "week".
Yes. The loop is stateless aside from the seen-URL store and can be scheduled at any interval. Running it hourly on a VPS or serverless function (AWS Lambda, Google Cloud Scheduler) provides near-real-time coverage. Be mindful of You.com API rate limits and Slack's ~1 message per second per channel limit to avoid burst errors.
Store the COMPETITORS list in an environment variable, a config file, or a HubSpot list that the loop reads at runtime. Pulling the list from HubSpot (e.g., companies tagged with a competitor label) keeps the tracked set in sync with your CRM without a code change. This assumes you've added a competitor option to the company Type property, or use a custom property—HubSpot's default Type options are Prospect, Partner, Reseller, and Vendor. You can query HubSpot for this list using the same One CLI HubSpot search action with a different filter:
one --agent actions execute hubspot <actionId> <hubspot_connection_key> \
--path-vars '{"objectType": "companies"}' \
-d '{
"after": "0",
"filterGroups": [{
"filters": [{
"propertyName": "type",
"operator": "EQ",
"value": "competitor"
}]
}],
"limit": 200,
"properties": ["name"],
"sorts": []
}'The get_crm_context function should return "CRM lookup failed" on error, which is passed through to the Slack alert. The alert still posts—the CRM label is enrichment, not a blocker. One CLI returns errors as JSON with an error key, so you can check for that in the response and log persistent issues.
Yes. The withone.ai platform supports tool-calling agents that can wrap each step (You.com search, HubSpot lookup, Slack post) as a discrete tool. The orchestrator loop above maps directly to a withone.ai agent definition, with the You.com Web Search API registered as the retrieval tool and HubSpot and Slack as action tools. The One CLI's --agent flag already produces structured JSON output designed for agent consumption, so the loop can be embedded directly into an agent's tool execution layer.
Yes. Modify the COMPETITORS query template and HIGH_SIGNAL_KEYWORDS list to target different event types. For pricing changes, include terms like "pricing", "plan", "tier", "discount". For leadership, include "CEO", "CTO", "appoints", "joins". Each event type can post to a separate Slack channel by mapping competitor + event type to a channel in a routing dict.
No. One CLI handles OAuth authentication for all connected platforms. Once you run one add <platform> and complete the browser-based auth flow, One stores and refreshes tokens automatically. The orchestrator script only needs the connection keys (opaque identifiers from one --agent connection list), not raw API credentials.
LI Test
URL CopiedLI Test
Share Article:
Related resources.

You.com + One: Automated Spend Scoring for Every Account in Your Salesforce Territory
June 15, 2026
Blog
.png)
You.com Web Intelligence Is Now Available in MindStudio’s Remy Apps
June 4, 2026
Blog
All resources.
Browse our complete collection of tools, guides, and expert insights — helping your team turn AI into ROI.

Context Window: Meaning and Optimization Tips
You.com Team
May 26, 2026
Blog
.png)
How APIs Became the Connective Tissue of LLMs
Brooke Grief
,
Head of Content & Web
May 20, 2026
Blog

Simple Abstractions, Dense Payloads: Tool Design for Agentic Search
Vincent Seng
,
Senior AI Engineer
May 18, 2026
Blog

Introducing the You.com Finance Research API: Agentic Research, No Infra Required
Rahul Mohan
,
Senior AI Engineer
May 14, 2026
Blog

Same LLM, Better Web Search, Better Outcome
Chak Pothina
,
Product Marketing Manager, APIs
May 7, 2026
Blog

What Is Semi Structured Data: A Developer's Guide
You.com Team
May 4, 2026
Blog
.png)
Context Rot Is Quietly Breaking Your API Integrations
Brooke Grief
,
Head of Content & Web
May 1, 2026
Blog

What Is a SERP API? Architecture, Limitations, and Why the Market Is Shifting
Brooke Grief
,
Head of Content & Web
April 30, 2026
Blog