Back to Competitor Monitoring

Developer Handover Pack

Everything needed to build the automation from scratch: current state, full agent specs, data flow, and the build stack.

4 pagesPDF · Technical
FS-DOC-04Technical

Developer Handover Pack

Competitor Monitoring Automation

[YourCompany.com] · Marketing Department · Prepared by FullSpec · [Today's Date]

This document gives the FullSpec build team everything needed to construct, wire, and ship the Competitor Monitoring automation end to end. It covers the current manual process that is being replaced, full specifications for both agents, the complete data flow from trigger to final output, and the recommended build stack with total time estimates. The owner side of this process is handled entirely by [YourCompany.com]'s marketing team. FullSpec owns all build, configuration, testing, and deployment work described here.

01Process snapshot

Step
Name
Description
1
Identify Competitors to Monitor
Marketing manager compiles the competitor list in Google Sheets, including URLs, social handles, and review page links. Updated inconsistently. Time cost: 20 min/week.
2
Check Competitor Websites Manually
BOTTLENECK: Team member visits each competitor homepage, pricing page, and product pages manually, taking informal notes. No structured output. Time cost: 60 min/week.
3
Review Google Alerts Inbox
Coordinator checks a shared or personal inbox for Google Alert notifications on competitor brand names and keywords. Items are skimmed and filed or ignored. Time cost: 15 min/week.
4
Pull SEO and Traffic Data
BOTTLENECK: Coordinator logs into SEMrush or Ahrefs, checks keyword ranking shifts, new backlinks, and ad copy changes per competitor, then copies data manually into the tracking sheet. Time cost: 45 min/week.
5
Check Social Media Profiles
Coordinator visits each competitor's LinkedIn, Facebook, and Instagram profiles looking for new posts, campaign launches, or follower growth signals. Findings noted informally. Time cost: 30 min/week.
6
Review Competitor Reviews and Ratings
Team checks Google Reviews, G2, or Trustpilot for new competitor reviews, identifying customer complaints or positive trends. Time cost: 20 min/week.
7
Consolidate Findings into Tracker
BOTTLENECK: All gathered data is manually entered into the shared Google Sheet, organised by competitor and date. Error-prone and frequently skipped when time is short. Time cost: 25 min/week.
8
Write Weekly Intelligence Summary
Marketing manager reads the tracker and writes a short summary covering key changes, risks, and opportunities. Time cost: 30 min/week.
9
Distribute Intelligence to Stakeholders
Summary is posted manually to a Slack channel or forwarded via email. No standard format; quality varies week to week. Time cost: 10 min/week.
Time cost summary: Total manual time per cycle is 255 minutes (4 hours 15 min), with a practical observed range of 4 to 5 hours/week. At 4.5 hours/week average that is approximately 18 hours/month and 225 hours/year across the marketing coordinator and marketing manager roles. Steps 3, 4, and 7 are fully replaced by the Data Collection Agent. Steps 8 and 9 are fully replaced by the Intelligence Summariser Agent. Steps 1, 2, 5, and 6 are either retained as lightweight human oversight or are out of scope for the Standard build.
Developer Handover PackPage 1 of 4
FS-DOC-04Technical

02Agent specifications

Data Collection Agent

This agent runs on a fixed weekly schedule and is responsible for pulling structured competitor intelligence from three external sources: SEMrush (keyword rankings, traffic estimates, paid ad keywords), Ahrefs (new backlinks, recently published content, domain rating changes), and Google Alerts (news mentions and press items via RSS). Outputs from all three sources are normalised into a single consistent JSON dataset keyed by competitor identifier before being staged for the Intelligence Summariser Agent. The agent must handle partial failures gracefully: if one source returns an error, it logs the failure and continues with available data rather than aborting the full run.

Trigger
Weekly schedule trigger, Monday 7:00 a.m. (local timezone configured at build time)
Tools
SEMrush API, Ahrefs API, Google Alerts RSS feeds
Replaces steps
Step 3 (Review Google Alerts Inbox), Step 4 (Pull SEO and Traffic Data), and partially Step 7 (Consolidate Findings into Tracker)
Estimated build
10 hours, Moderate complexity
// Input
trigger: { schedule: 'CRON 0 7 * * 1', timezone: 'America/New_York' }
config: {
  competitors: GoogleSheets.range('CompetitorList!A2:E') -> [
    { competitor_id: string, name: string, domain: string, semrush_domain: string, ahrefs_target: string }
  ],
  alerts_rss_urls: GoogleSheets.range('AlertFeeds!A2:B') -> [
    { competitor_id: string, rss_url: string }
  ],
  lookback_days: 7
}

// Output
staged_dataset: {
  run_id: uuid,
  run_timestamp: ISO8601,
  competitors: [
    {
      competitor_id: string,
      name: string,
      domain: string,
      semrush: {
        organic_keywords_delta: integer,
        estimated_traffic_delta: integer,
        new_paid_keywords: [ { keyword: string, position: integer } ],
        data_status: 'ok' | 'error' | 'partial'
      },
      ahrefs: {
        new_backlinks: [ { source_domain: string, target_url: string, dr: integer } ],
        new_content_urls: [ { url: string, title: string, published_date: date } ],
        dr_change: integer,
        data_status: 'ok' | 'error' | 'partial'
      },
      alerts: [
        { title: string, url: string, source: string, published_date: date }
      ],
      source_errors: [ { source: string, error_message: string } ]
    }
  ]
}
  • SEMrush API access requires a Guru plan or above for full API access including domain analytics endpoints. Confirm the current subscription tier before scoping; the Business plan increases the daily API unit cap from 10,000 to 50,000, which matters if tracking more than 5 competitors. Use the /domain/organic/competitors endpoint for ranking data and /domain/adwords/keywords for paid keywords.
  • Ahrefs API access is only available on the Advanced plan or above. Confirm this with the client before build start. Use the /v3/site-explorer/new-backlinks endpoint with the mode=subdomains parameter. Set the date_from field to exactly 7 days before the run timestamp to avoid duplicates across cycles.
  • Google Alerts RSS feeds must be manually created and stored in the AlertFeeds tab of the Google Sheet. The automation reads these URLs at runtime. The build team must verify each URL returns a valid RSS 2.0 response before marking the agent complete.
  • Normalisation: all competitor data must be keyed by a stable competitor_id (e.g. 'comp_001') that matches the value in the CompetitorList sheet. This ID is the join key for the downstream agent and the Sheets tracker.
  • Deduplication: backlink entries should be deduplicated against the previous run's output using source_domain + target_url as the composite key. Store the previous run's ahrefs backlink list in a persistent cache (Supabase table: competitor_backlink_cache) keyed by run_week.
  • Fallback behaviour: if SEMrush or Ahrefs returns a non-2xx response after two retries, set data_status to 'error', populate source_errors, and continue. The summariser must handle missing source blocks gracefully and note the gap in the digest.
  • Confirm with the marketing manager before build: what is the full list of competitors to track, and are all required Google Alert RSS feeds already configured? This is a hard dependency before the agent can be fully wired.
Intelligence Summariser Agent

This agent receives the staged JSON dataset produced by the Data Collection Agent and uses an AI language model to write a structured weekly intelligence digest in plain English. The digest includes a highlights section covering the most significant changes across all competitors, followed by one section per tracked competitor. The agent also applies a significance threshold: if any single metric change exceeds a defined threshold (e.g. DR change greater than or equal to 5, organic traffic delta greater than or equal to 15%, or more than 3 new high-DR backlinks), the run is flagged for human review by the marketing manager before distribution. Regardless of the flag outcome, the digest is always appended to the Google Sheet tracker and posted to Slack. A summary note is also logged in HubSpot against the designated marketing campaign record.

Trigger
Data Collection Agent completes successfully and stages the run dataset (run_id confirmed in Supabase staging table)
Tools
AI language model (LLM via API), Google Sheets, Slack, HubSpot
Replaces steps
Step 7 (Consolidate Findings into Tracker), Step 8 (Write Weekly Intelligence Summary), Step 9 (Distribute Intelligence to Stakeholders)
Estimated build
8 hours, Moderate complexity
// Input
staged_dataset: { run_id, run_timestamp, competitors: [ ... ] }  // from Data Collection Agent
prompt_config: {
  digest_format: 'section_per_competitor_with_highlights',
  highlight_count: 5,
  significance_rules: {
    dr_change_threshold: 5,
    traffic_delta_pct_threshold: 15,
    new_high_dr_backlinks_threshold: 3,
    high_dr_minimum: 60
  },
  tone: 'concise, factual, actionable',
  max_tokens_per_competitor: 300
}

// Output
digest: {
  run_id: uuid,
  week_ending: date,
  significant_change_flagged: boolean,
  flag_reason: string | null,
  highlights_markdown: string,
  competitor_sections: [
    {
      competitor_id: string,
      name: string,
      summary_markdown: string,
      key_metrics: {
        organic_keywords_delta: integer,
        traffic_delta: integer,
        new_backlinks_count: integer,
        new_content_count: integer,
        alert_count: integer
      }
    }
  ]
}

// On approval (significant_change_flagged = true)
// Marketing manager receives a Slack DM with the flag reason and a prompt to review
// The digest is held in a 'pending_review' state in Supabase for up to 4 hours
// If no response is received within 4 hours, the digest is published automatically
// and the flag is logged in the competitor_runs audit table with status 'auto_released'
slack_dm_payload: {
  channel: '@marketing_manager_slack_id',
  text: 'Significant change flagged in this week\'s competitor digest. Reason: {flag_reason}. Please review before 11 a.m. or it will publish automatically.',
  action_buttons: [ 'Approve and publish', 'Edit before publishing' ]
}

google_sheets_append: {
  sheet: 'WeeklyLog',
  row: [ week_ending, competitor_name, organic_keywords_delta, traffic_delta,
         new_backlinks_count, new_content_count, alert_count, significant_change_flagged ]
}

slack_channel_post: {
  channel: '#competitor-intelligence',
  main_message: highlights_markdown,
  thread_replies: [ competitor_sections[0..n].summary_markdown ]
}

hubspot_note: {
  object_type: 'company' | 'deal',
  object_id: configured_hubspot_record_id,
  note_body: 'Weekly competitor digest logged. Week ending {week_ending}. Significant flag: {significant_change_flagged}.'
}
  • The AI prompt template must be stored as a versioned string in the build configuration, not hardcoded. This allows the marketing manager to request prompt adjustments without a redeploy. Store the active prompt version in a Supabase config table (table: agent_config, key: summariser_prompt_v).
  • The Slack integration requires a bot token with the chat:write and im:write OAuth scopes. The Slack channel '#competitor-intelligence' must exist and the bot must be invited before the first live run. The marketing manager's Slack user ID must be confirmed and stored in the credential store before build.
  • Google Sheets append uses the Sheets API v4 with an OAuth 2.0 service account. The service account must be granted Editor access to the tracker spreadsheet. Sheet name is 'WeeklyLog'; confirm the exact spreadsheet ID with the client before wiring.
  • HubSpot note logging uses the CRM Notes API (POST /crm/v3/objects/notes). The associated object type (company or deal) and the specific record ID must be confirmed with the marketing manager before build. Use a private app token; do not use OAuth for this integration.
  • The significance flagging logic must be implemented in the orchestration layer before the LLM call, using the raw numeric fields from the staged dataset. Do not rely on the LLM to determine whether a flag is warranted.
  • If significant_change_flagged is true, the Slack DM must fire before the channel post. The 4-hour auto-release window is a hard requirement confirmed with the process owner.
  • Confirm before build: the HubSpot record ID to log notes against, the exact Slack channel name, the Google Sheets spreadsheet ID, and whether the LLM provider preference is OpenAI GPT-4o or an alternative.
Developer Handover PackPage 2 of 4
FS-DOC-04Technical

03End-to-end data flow

Full trigger-to-output data flow, Competitor Monitoring Automation
// ── TRIGGER ────────────────────────────────────────────────────────────────
schedule_trigger: CRON '0 7 * * 1'  // Monday 7:00 a.m.
  -> emit: { run_id: uuid, run_timestamp: ISO8601 }

// ── DATA COLLECTION AGENT ──────────────────────────────────────────────────
// Step 1: Load competitor config from Google Sheets
GoogleSheets.get('CompetitorList!A2:E') -> competitors[]
  fields: [ competitor_id, name, domain, semrush_domain, ahrefs_target ]

GoogleSheets.get('AlertFeeds!A2:B') -> alert_feeds[]
  fields: [ competitor_id, rss_url ]

// Step 2: Fetch SEMrush data (per competitor, parallelised)
FOR each competitor IN competitors[]:
  SEMrush.GET /domain/organic/competitors
    params: { domain: competitor.semrush_domain, date_from: run_date-7d }
    -> semrush_raw: { keywords_delta, traffic_delta, paid_keywords[] }
    on_error: set data_status='error', log to source_errors[], continue

// Step 3: Fetch Ahrefs data (per competitor, parallelised)
FOR each competitor IN competitors[]:
  Ahrefs.GET /v3/site-explorer/new-backlinks
    params: { target: competitor.ahrefs_target, mode: 'subdomains', date_from: run_date-7d }
    -> ahrefs_raw: { backlinks[], new_content[], dr_change }
    dedup: backlinks[] AGAINST Supabase.competitor_backlink_cache
      key: source_domain + target_url
    on_error: set data_status='error', log to source_errors[], continue

// Step 4: Fetch Google Alerts RSS (per alert feed URL)
FOR each feed IN alert_feeds[]:
  HTTP.GET feed.rss_url
    -> rss_raw: RSS2.0 XML
    parse: items[] -> { title, url, source, published_date }
    filter: published_date >= run_date-7d
    -> alerts[competitor_id]

// Step 5: Normalise and stage
normalise(semrush_raw, ahrefs_raw, alerts[]) ->
  staged_dataset: {
    run_id, run_timestamp,
    competitors[]: {
      competitor_id, name, domain,
      semrush: { organic_keywords_delta, estimated_traffic_delta, new_paid_keywords[], data_status },
      ahrefs: { new_backlinks[], new_content_urls[], dr_change, data_status },
      alerts: [ { title, url, source, published_date } ],
      source_errors[]
    }
  }

Supabase.INSERT competitor_runs:
  { run_id, run_timestamp, status: 'staged', competitor_count: n }

// ── AGENT HANDOFF: Data Collection Agent -> Intelligence Summariser Agent ──
// Trigger condition: Supabase.competitor_runs WHERE run_id = current AND status = 'staged'

// ── INTELLIGENCE SUMMARISER AGENT ─────────────────────────────────────────
// Step 6: Evaluate significance thresholds (pre-LLM, in orchestration layer)
FOR each competitor IN staged_dataset.competitors[]:
  IF competitor.ahrefs.dr_change >= 5
  OR competitor.semrush.estimated_traffic_delta >= 15%
  OR COUNT(competitor.ahrefs.new_backlinks WHERE dr >= 60) >= 3:
    significant_change_flagged = true
    flag_reason = '<competitor.name>: <reason>'

// Step 7: LLM digest generation
LLM.complete(
  model: 'gpt-4o',
  prompt: Supabase.agent_config['summariser_prompt_v'],
  input: staged_dataset,
  max_tokens_per_competitor: 300
) ->
  digest: {
    highlights_markdown,
    competitor_sections[]: { competitor_id, name, summary_markdown, key_metrics{} }
  }

// Step 8: Conditional flag handling
IF significant_change_flagged:
  Slack.postDirectMessage(
    to: config.marketing_manager_slack_id,
    text: 'Significant change flagged: {flag_reason}. Approve by 11 a.m. or auto-publishes.',
    buttons: ['Approve and publish', 'Edit before publishing']
  )
  Supabase.UPDATE competitor_runs SET status='pending_review'
  WAIT max 4 hours for approval webhook
    on_approval: continue to Step 9
    on_timeout: continue to Step 9, log status='auto_released'
ELSE:
  continue to Step 9

// ── OUTPUTS ───────────────────────────────────────────────────────────────
// Step 9a: Append to Google Sheets tracker
GoogleSheets.append('WeeklyLog', row: [
  week_ending, competitor_id, competitor_name,
  organic_keywords_delta, traffic_delta,
  new_backlinks_count, new_content_count, alert_count,
  significant_change_flagged
])

// Step 9b: Post digest to Slack channel
Slack.postMessage(
  channel: '#competitor-intelligence',
  text: digest.highlights_markdown,
  thread: digest.competitor_sections[].summary_markdown
)

// Step 9c: Log note in HubSpot
HubSpot.POST /crm/v3/objects/notes
  body: {
    properties: {
      hs_note_body: 'Competitor digest week ending {week_ending}. Flag: {significant_change_flagged}.',
      hs_timestamp: run_timestamp
    },
    associations: [ { objectType: config.hubspot_object_type, id: config.hubspot_record_id } ]
  }

// Step 10: Finalise run record
Supabase.UPDATE competitor_runs
  SET status='complete', completed_at=now()
  WHERE run_id = current_run_id
Developer Handover PackPage 3 of 4
FS-DOC-04Technical

04Recommended build stack

Orchestration layer
A workflow automation tool (platform TBD at build kick-off). Structure as two discrete workflows: one per agent, each independently triggerable and debuggable. Both workflows share a single credential store. No credentials are hardcoded in workflow nodes.
Webhook configuration
A webhook endpoint is required to receive the marketing manager's approval or edit response from the Slack interactive button payload. The endpoint must validate the Slack signing secret on every inbound request. URL must be HTTPS with a valid certificate. Register the webhook URL in the Slack app manifest under 'Interactivity and Shortcuts' before go-live.
Templating approach
The AI summariser prompt is stored as a versioned plain-text string in Supabase (table: agent_config, column: prompt_body, column: prompt_version). The orchestration layer fetches the active version at runtime by querying WHERE is_active = true. Slack message formatting uses Slack Block Kit JSON for the main channel post, with competitor sections posted as threaded replies using plain markdown.
Error logging
All agent errors are written to a Supabase table: automation_error_log (columns: run_id, agent_name, step_label, error_code, error_message, timestamp, resolved). On any critical failure (e.g. both SEMrush and Ahrefs return errors in the same run, or the LLM call fails), an alert is posted to a '#automation-alerts' Slack channel. Non-critical partial failures (one source erroring while others succeed) are logged silently and included in the digest as a data gap note.
Testing approach
All agent workflows are built and validated in a sandbox environment first. SEMrush and Ahrefs sandbox/test modes are used where available; otherwise, a static fixture JSON file representing a two-competitor dataset is used for the Data Collection Agent output. The Intelligence Summariser Agent is tested against this fixture before any live API call is made. Three full weekly cycles are run in test mode before go-live, with digest output reviewed by the marketing manager against manual spot checks.
Data persistence
Supabase is used for: run records (competitor_runs), error logging (automation_error_log), backlink deduplication cache (competitor_backlink_cache), agent configuration (agent_config), and pending-review state management. Google Sheets (WeeklyLog tab) is the human-readable historical record. Supabase is not a replacement for the Google Sheet; both are written on every successful run.
Credential store entries required
SEMrush API key, Ahrefs API key, Google Sheets OAuth 2.0 service account JSON, Slack bot token (chat:write + im:write scopes), Slack signing secret (for webhook verification), HubSpot private app token, LLM provider API key (OpenAI or alternative), Supabase project URL and service role key.
Estimated total build time
Data Collection Agent: 10 hours. Intelligence Summariser Agent: 8 hours. End-to-end integration testing and QA (three full test cycles, prompt tuning, edge case handling): 4 hours. Total: 22 hours.
Before the first line of build work begins, the following must be confirmed in writing: (1) SEMrush and Ahrefs subscription tiers include API access. (2) The full competitor list and Google Alert RSS URLs are finalised and loaded into the Google Sheet. (3) The Slack channel '#competitor-intelligence' exists and the Slack app bot has been invited. (4) The HubSpot record ID and object type for note logging are agreed. (5) The marketing manager's Slack user ID is confirmed for DM delivery. Any of these items left unconfirmed at build start will cause delays. Contact FullSpec at support@gofullspec.com if there are blockers on access provisioning.
Developer Handover PackPage 4 of 4

More documents for this process

Every document generated for Competitor Monitoring.

Launch Plan
Operations · Owner
View
ROI and Business Case
Finance · Owner
View
Process Runbook / SOP
Operations · Owner
View
Integration and API Spec
Technical · Developer
View
Test and QA Plan
Quality · Developer
View