beginner PythonFreshGeo SDKSlack
Overnight competitor pricing agent
Wakes at 2am, pulls pricing for your tracked SKUs across 12 competitors, writes a diff to Slack if anything moved more than 3%.
PricingCompetitor Monitoring
from freshgeo import FreshGeo
from slack_sdk import WebClient
import os
fg = FreshGeo(api_key=os.environ["FG_KEY"])
slack = WebClient(token=os.environ["SLACK_TOKEN"])
skus = ["DYSON-V15", "SHARK-IZ420", "MIELE-C3"]
competitors = ["currys.co.uk", "argos.co.uk", "ao.com"]
moves = []
for sku in skus:
result = fg.pricing.compare(sku=sku, sources=competitors)
for row in result.offers:
if abs(row.change_pct_24h) >= 3.0:
moves.append(f"{sku} @ {row.source}: {row.price} ({row.change_pct_24h:+.1f}%)")
if moves:
slack.chat_postMessage(channel="#pricing", text="\n".join(moves)) Why it matters. Replaces a manual pricing analyst morning routine. One retailer saved 11 hours a week and caught a 4am price drop that would have cost them £40k of margin.
intermediate TypeScriptClaudeMCP
Pre-call research brief
Given a company domain, produces a one-page brief covering funding, headcount trend, recent hiring, competitor mentions and buying signals.
IntentJobsSocialNews/Risk
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const brief = await client.messages.create({
model: "claude-sonnet-4-7",
max_tokens: 2000,
mcp_servers: [{
type: "url",
url: "https://mcp.freshgeo.com",
authorization_token: process.env.FG_KEY
}],
messages: [{
role: "user",
content: `Build a pre-call brief for monzo.com. Pull hiring, press, intent signals around 'fraud detection', and exec activity. Output as markdown with a 3-bullet 'what to ask' section.`
}]
});
console.log(brief.content[0].text); Why it matters. AEs walk into calls with context the prospect actually recognises. A mid-market SaaS sales team saw reply rates go from 3.1% to 7.4% on cold outreach using these briefs.
intermediate PythonFreshGeo SDK
Buyer-criteria property matcher
Natural language buyer brief → filtered list of UK properties with commute times, catchment scores and negotiation signals like days-on-market.
Real Estate
from freshgeo import FreshGeo
fg = FreshGeo(api_key="...")
brief = {
"location": "SE London, within 40min commute of Liverpool Street",
"beds_min": 3,
"budget_max_gbp": 750000,
"must_have": ["garden", "period_features"],
}
matches = fg.real_estate.search(**brief, limit=25)
for p in matches:
signal = "negotiable" if p.days_on_market > 60 else "firm"
print(f"{p.address} — £{p.price:,} — {p.beds}bd — {p.commute_min}min — {signal}") Why it matters. A boutique buying agency replaced a junior analyst with this. Clients get 15 qualified properties in 8 seconds instead of a shortlist two days later.
advanced PythonPostgres
Supplier KYC refresh
Weekly sweep of all active suppliers checking for sanctions, adverse media, ownership changes and director resignations. Flags anything material.
News/Risk
import psycopg2
from freshgeo import FreshGeo
fg = FreshGeo(api_key="...")
db = psycopg2.connect(dsn=DB_DSN)
with db.cursor() as cur:
cur.execute("SELECT id, legal_name, companies_house_id FROM suppliers WHERE status='active'")
suppliers = cur.fetchall()
for sid, name, ch_id in suppliers:
risk = fg.news_risk.scan(
entity=name,
companies_house_id=ch_id,
categories=["sanctions", "adverse_media", "ownership_change"],
since="7d"
)
if risk.max_severity >= 3:
cur.execute(
"INSERT INTO kyc_flags (supplier_id, severity, summary, cache_id) VALUES (%s,%s,%s,%s)",
(sid, risk.max_severity, risk.summary, risk.cache_id)
)
db.commit() Why it matters. Turns quarterly KYC reviews into weekly ones without adding headcount. A fintech caught a sanctioned beneficial owner 11 weeks before their old process would have.
advanced Pythonpandas
Emerging category detector
Scans product listings, job posts and social chatter for a category and surfaces fast-growing subsegments before they show up in analyst reports.
SocialJobsCompetitor Monitoring
from freshgeo import FreshGeo
import pandas as pd
fg = FreshGeo(api_key="...")
category = "home espresso"
signals = fg.social.trends(category=category, window="90d", geo="GB")
hiring = fg.jobs.search(keywords=[category], posted_since="90d")
df = pd.DataFrame({
"subsegment": [s.term for s in signals],
"social_growth": [s.growth_pct for s in signals],
"hiring_growth": [hiring.by_term.get(s.term, 0) for s in signals],
})
df["score"] = df.social_growth * 0.5 + df.hiring_growth * 0.5
print(df.sort_values("score", ascending=False).head(10)) Why it matters. A consumer VC uses this to shortlist seed deals. They found three companies in the prosumer grinder space six months before the category broke into mainstream press.
beginner TypeScriptResend
Weekly competitor changelog
Monitors pricing pages, feature pages and docs for every named competitor. Emails a structured diff every Monday with deletions, additions and price changes.
Competitor Monitoring
import { FreshGeo } from "@freshgeo/node";
import { Resend } from "resend";
const fg = new FreshGeo({ apiKey: process.env.FG_KEY! });
const resend = new Resend(process.env.RESEND_KEY!);
const competitors = ["stripe.com", "adyen.com", "checkout.com"];
const paths = ["/pricing", "/features", "/docs/webhooks"];
const diffs = [];
for (const domain of competitors) {
for (const path of paths) {
const d = await fg.competitorMonitoring.diff({ url: `https://${domain}${path}`, window: "7d" });
if (d.has_changes) diffs.push(d);
}
}
await resend.emails.send({
from: "intel@acme.co", to: "product@acme.co",
subject: "Competitor changelog",
html: diffs.map(d => `<h3>${d.url}</h3><ul>${d.changes.map(c => `<li>${c.summary}</li>`).join("")}</ul>`).join(""),
}); Why it matters. PMs stop tab-hopping through competitor sites. One Series B team ships responses to competitor launches in 48 hours instead of two weeks.
intermediate PythonCSV
ICP account scorer
Takes a CSV of target accounts, enriches each with firmographic + intent + hiring signals, returns a 0-100 score your SDRs can sort by.
IntentJobsSocial
import csv
from freshgeo import FreshGeo
fg = FreshGeo(api_key="...")
def score(domain: str) -> dict:
intent = fg.intent.lookup(domain=domain, topics=["data platform"])
jobs = fg.jobs.count(domain=domain, roles=["data engineer"], since="30d")
points = min(intent.score, 40) + min(jobs * 5, 30)
return {"domain": domain, "score": points, "cache_ids": [intent.cache_id, jobs.cache_id]}
with open("targets.csv") as f, open("scored.csv", "w", newline="") as out:
writer = csv.DictWriter(out, fieldnames=["domain", "score", "cache_ids"])
writer.writeheader()
for row in csv.DictReader(f):
writer.writerow(score(row["domain"])) Why it matters. SDRs stop wasting mornings on dead accounts. A RevOps team reallocated 38% of outbound capacity to the top-scoring decile and lifted meetings booked by 2.2x.
beginner Claude DesktopMCP
Always-on market monitor via MCP
Wires FreshGeo into Claude Desktop as an MCP server. Ask 'what moved in UK EV charging this week?' in chat and get a sourced answer.
News/RiskCompetitor MonitoringJobs
// ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"freshgeo": {
"command": "npx",
"args": ["-y", "@freshgeo/mcp-server"],
"env": {
"FRESHGEO_API_KEY": "fg_live_...",
"FRESHGEO_ALLOWED_APIS": "news_risk,competitor_monitoring,jobs",
"FRESHGEO_DAILY_CAP_GBP": "5"
}
}
}
}
// Then in Claude Desktop:
// "Using freshgeo, tell me what moved in UK EV charging this week.
// Group by company, cite sources, and flag any funding or regulatory signals." Why it matters. Analysts get a live market monitor without building an app. A strategy team at a FTSE 250 uses this daily — cost per analyst is under £3 a week.