# Competitor Content Tracker (`arched_friend/competitor-content-tracker`) Actor

Track everything your competitors publish. New blog posts and articles from any list of sites, with title, link, publish date, author and summary, found automatically through their feeds or sitemaps.

- **URL**: https://apify.com/arched\_friend/competitor-content-tracker.md
- **Developed by:** [Peach O](https://apify.com/arched_friend) (community)
- **Categories:** SEO tools, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 post founds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Competitor Content Tracker: Everything They Publish, In One Feed

**Watch what every competitor publishes without visiting a single blog.**

Content teams find out what the competition shipped when a colleague forwards a link, usually a fortnight late. The information was public the whole time. It just was not collected anywhere.

Give this a list of sites and get every post they published, newest first, with the title, link, date, author, summary and topic tags. The Actor works out where each site publishes on its own, so you never have to hunt for a feed URL.

Built for content marketers tracking a category, SEO teams watching what a rival ranks for next, product marketers on competitive intelligence, and anyone who has to write a weekly "what changed" update.

### How it works

```mermaid
flowchart TB
    A[Site list] --> B[Read the home page]
    B --> C{Feed declared<br/>in the head?}
    C -->|yes| F[Parse the feed]
    C -->|no| D{Feed at a<br/>common path?}
    D -->|yes| F
    D -->|no| E{Sitemap?}
    E -->|yes| G[Read sitemap,<br/>keep article URLs]
    E -->|no| H[Reported as<br/>nothing found]
    F --> I[Filter by date<br/>and keywords]
    G --> I
    I --> J[(Your content feed)]
```

Discovery runs in that order because it moves from most reliable to least. A feed the site advertises is authoritative, a feed at a conventional path is nearly always right, and a sitemap is a last resort that still beats nothing. Whatever it used, the row tells you.

### What you get

One row per post. A real row from a live run:

```json
{
  "site": "github.blog",
  "title": "How we make AI coding more cost efficient without sacrificing task quality",
  "url": "https://github.blog/ai-and-ml/github-copilot/how-we-make-ai-coding-more-cost-efficient/",
  "publishedAt": "2026-09-02T18:00:00.000Z",
  "dateMeaning": "published",
  "author": "Erik Kristensen",
  "summary": "Why shorter outputs can cost more, and how GitHub Copilot reduces wasted work across the complete coding task.",
  "categories": ["AI & ML", "Engineering", "GitHub Copilot", "LLMs"],
  "sourceType": "feed",
  "sourceUrl": "https://github.blog/feed/"
}
```

### Dates mean what they say

A feed publishes a real publish date. A sitemap publishes `lastmod`, which is when the page last changed, and a page can change years after it was written. Both land in `publishedAt`, and `dateMeaning` says which one you are looking at, so a refreshed old page is never mistaken for something new.

### Watching a topic instead of a whole blog

Add `keywords` and only posts mentioning those terms in the title, summary or tags come through. This is the difference between tracking a competitor and tracking a competitor's pricing announcements.

```json
{
  "sites": ["competitor.com", "otherrival.com"],
  "days": 7,
  "keywords": ["pricing", "acquisition", "funding", "launch"],
  "onlyNewPosts": true
}
```

Put that on a weekly schedule with `onlyNewPosts` on and the dataset becomes a digest that only ever contains things you have not seen.

### Run it from the command line

```bash
curl -X POST "https://api.apify.com/v2/acts/arched_friend~competitor-content-tracker/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "sites": ["blog.cloudflare.com", "github.blog"],
    "days": 30,
    "maxPostsPerSite": 20
  }'
```

### Pricing

$0.003 per post returned. A site that published nothing in the window costs nothing.

| | This Actor | Content monitoring SaaS | RSS reader |
| --- | --- | --- | --- |
| 20 sites, weekly | about $1 a month | $50 to $300 a month | Free, but no data out |
| Finds the feed for you | Yes | Sometimes | You paste each one |
| Works without a feed | Sitemap fallback | Rarely | No |
| Keyword filtering | Yes | Yes | Limited |
| Data you own | Dataset, API, webhook | Their dashboard | In the reader |

### Notes and limits

- Some sites publish neither a feed nor a usable sitemap. Those are reported in the run summary under `sitesWithNothing` with the reason, rather than failing the run.
- Sitemap rows have no title, because a sitemap lists URLs and nothing else. The URL and the date are still there.
- Feeds usually carry the ten to fifty most recent posts, so a very long lookback returns whatever the feed still holds rather than the full archive.
- Very large feeds are read up to a size cap so one enormous file cannot dominate a run.

### Related products

- **Brand Mention Monitor** for when your competitors are written about elsewhere.
- **Hacker News Brand Monitor** for the same watch on Hacker News.
- **Tech Stack Checker** for what those same competitors are running under the hood.

# Actor input Schema

## `sites` (type: `array`):

The sites to watch, one per line. A bare domain or a full URL both work. The Actor finds the feed itself, so there is no need to know where it lives.

## `days` (type: `integer`):

Only return posts published in this window. Set it to match your schedule, so a weekly run looks back seven days.

## `keywords` (type: `array`):

Optional filter. Keep only posts whose title, summary or categories mention one of these terms, which is how you watch for a topic rather than a whole blog.

## `onlyNewPosts` (type: `boolean`):

Remember what has already been reported and return only posts that are new. Turn this on for a scheduled run so the dataset works as an alert feed.

## `maxPostsPerSite` (type: `integer`):

Caps how many posts to keep from each site, newest first, which also caps what a run can cost.

## `allowSitemapFallback` (type: `boolean`):

When a site publishes no feed, read its sitemap instead. Sitemap rows carry a last modified date rather than a publish date, and the row says so.

## `timeoutSeconds` (type: `integer`):

How long to wait for each page or feed before moving on to the next candidate.

## Actor input object example

```json
{
  "sites": [
    "blog.cloudflare.com",
    "github.blog",
    "openai.com"
  ],
  "days": 30,
  "onlyNewPosts": false,
  "maxPostsPerSite": 50,
  "allowSitemapFallback": true,
  "timeoutSeconds": 20
}
```

# Actor output Schema

## `posts` (type: `string`):

One row per post, newest first, with the title, link, publish date, author, summary and categories.

## `runSummary` (type: `string`):

Post counts per site, the newest posts across all of them, and which sites had a feed, needed the sitemap, or published neither.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "sites": [
        "blog.cloudflare.com",
        "github.blog",
        "openai.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("arched_friend/competitor-content-tracker").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "sites": [
        "blog.cloudflare.com",
        "github.blog",
        "openai.com",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("arched_friend/competitor-content-tracker").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "sites": [
    "blog.cloudflare.com",
    "github.blog",
    "openai.com"
  ]
}' |
apify call arched_friend/competitor-content-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,arched_friend/competitor-content-tracker"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/4yT2vozkkwLOG46hc/builds/TmPnJ92eQN0IGLAuO/openapi.json
