# Shopify Blog Tracker — Articles, Dates & Publishing Activity (`tidyfeed/shopify-blog-tracker`) Actor

See what any Shopify store publishes on its blog. Every article the store lists, newest first, with full text on the recent ones. Reads the store's own sitemap so you get the real article count, not just the last 30.

- **URL**: https://apify.com/tidyfeed/shopify-blog-tracker.md
- **Developed by:** [tidyfeed](https://apify.com/tidyfeed) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.50 / 1,000 articles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## Shopify Blog Tracker — Articles, Dates & Publishing Activity

**What is this brand actually publishing?**

Every article a Shopify store lists, newest first, with the full text on the recent ones. Point it at a list of competitors and read a season of their content strategy in one sheet.

No API key. No login. No Shopify partner account. No proxies.

***

### The number other tools cannot give you

Shopify serves blog posts through an Atom feed. **That feed stops at 30 posts per blog**, and paging parameters are ignored — `?page=2` and `?page=3` return byte-identical responses with the same 30 articles. Measured 2 September 2026.

So a tool built on the feed alone tells you a store has 30 posts. Here is what these stores actually publish:

| Store | Articles published | What the feed alone returns |
|---|---|---|
| deathwishcoffee.com | **368** across 8 blogs | 122 |
| rothys.com | **3,852** | ~30 per blog |
| allbirds.com | **80** | 80 |

This actor reads the store's own sitemap as well, so **`blogArticlesTotal` is the real count** and you can see at a glance whether a brand publishes weekly or has posted twice since 2023.

***

### What you get

One row per article:

**Which blog** — `blogHandle`, `blogTitle`, `blogArticlesTotal`

**The article** — `articleTitle`, `articleUrl`, `imageUrl`, `summary`, `author`, `tags`

**When** — `publishedAt`, `daysSincePublished`, `lastModified`, `daysSinceModified`

**How complete** — `hasFullText`, and the body itself when you ask for it

***

### Two modes

**Default — recent articles, complete.** Everything the Atom feed covers: full text, author, tags, real publish dates. This is the mode for tracking activity.

**Archive on — everything the store lists.** Adds every older article from the sitemap: title, URL, image and modification date. `hasFullText` is `false` on those rows and **`publishedAt` is left empty**, because a modification date is not a publish date and this actor does not pretend otherwise.

Run it on deathwishcoffee.com and the default gives 122 articles; archive on gives all 368.

***

### Typical uses

- **Compare content cadence across a category.** Twenty brands, sorted by `blogArticlesTotal` and last publish date. Who is investing in content and who quietly stopped.
- **Watch a competitor week by week.** Set the day filter to 7 and schedule it.
- **Find the topics a brand keeps returning to.** Tags and titles across the whole archive.
- **Feed a content brief.** Recent articles come with the body text.

***

### Input

| Field | What it does |
|---|---|
| `storeUrls` | The stores to read. Normal website addresses. |
| `daysBack` | 0 for everything, or a window — 7 for a weekly check. |
| `includeArchive` | Add every older article the sitemap lists, without body text. |
| `includeBody` | Add the article text. Only recent articles have one. |
| `maxArticlesPerStore` | Upper limit per store. Large brands publish thousands. |

***

### What it costs

Billed per article delivered. **A store with no blog returns nothing and costs nothing** beyond the run start — and plenty of stores have blogs with nothing in them.

Platform usage is included. No proxies are needed, so there are no proxy costs.

***

### How it works

Two public sources, combined:

1. **`sitemap.xml` → `sitemap_blogs_N.xml`** — every blog, every article, with titles and modification dates. This is where the real count comes from.
2. **`/blogs/<handle>.atom`** — the 30 most recent posts per blog, with full text, author, tags and publish dates.

**Headless storefronts are followed to their real shop.** Brands running a custom front end are resolved to the Shopify shop named in their own markup — mejuri.com resolves this way.

Both sources are XML the store publishes for search engines. No HTML parsing means a theme change cannot break it.

***

### Honest limits

- **Only the 30 most recent posts per blog carry body text, an author and a publish date.** This is Shopify's limit, not a design choice — see the measurement above. Older rows are marked `hasFullText: false`.
- **`lastModified` is a modification date, not a publish date.** A 2019 article edited last month shows last month. It is reported under its own name and never copied into `publishedAt`.
- **Blogs with no articles are common.** gymshark.com publishes 10 blogs and 0 articles. The run reports that rather than failing, and bills nothing.
- **Stores with no blog sitemap have no blog**, and are reported per store.
- **Article counts come from what the store publishes to search engines.** Unpublished drafts and hidden posts are not there — which is correct, but it is not the store's admin view.

***

### Scheduling

Content programmes run in quarters. Schedule this monthly against a competitor list and the archive count plus last publish date tells you who is still investing — usually before it shows up anywhere else.

Pair it with `tidyfeed/shopify-new-arrivals` for product launches and `tidyfeed/shopify-store-report` for the commercial picture.

***

### Legal

This actor reads only data a Shopify store publishes publicly, at addresses the store itself serves to search engines. It collects no personal data, requires no login, and bypasses no access control. You remain responsible for how you use the exported data.

***

Questions, or a store that behaves oddly? Open an issue on the actor — issues are read and answered.

# Actor input Schema

## `storeUrls` (type: `array`):

The stores to read. Paste normal website addresses — https://deathwishcoffee.com. No API key, login or Shopify partner account is needed. Stores running a custom front end are resolved to their Shopify shop automatically.

## `daysBack` (type: `integer`):

Leave at 0 for no date filter. Set 30 for a monthly content check, 7 for a weekly one.

## `includeArchive` (type: `boolean`):

Off by default, which returns the recent articles that come with full text. Turn it on and every article the store's sitemap lists is added too — title, URL, image and modification date, but no body. Shopify only serves the body for the 30 most recent posts per blog, so this is the honest limit rather than a missing feature.

## `includeBody` (type: `boolean`):

Add the full article text. Only the recent articles have one. Off by default because it makes spreadsheets hard to read.

## `maxArticlesPerStore` (type: `integer`):

Upper limit per store. Large brands publish thousands — rothys.com lists over 3,800.

## Actor input object example

```json
{
  "storeUrls": [
    "https://deathwishcoffee.com",
    "https://rothys.com"
  ],
  "daysBack": 0,
  "includeArchive": false,
  "includeBody": false,
  "maxArticlesPerStore": 1000
}
```

# Actor output Schema

## `articles` (type: `string`):

No description

## `articlesCsv` (type: `string`):

No description

# 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 = {
    "storeUrls": [
        "https://deathwishcoffee.com"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tidyfeed/shopify-blog-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 = { "storeUrls": ["https://deathwishcoffee.com"] }

# Run the Actor and wait for it to finish
run = client.actor("tidyfeed/shopify-blog-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 '{
  "storeUrls": [
    "https://deathwishcoffee.com"
  ]
}' |
apify call tidyfeed/shopify-blog-tracker --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tidyfeed/shopify-blog-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/I2oaTjKfN8fRhIafG/builds/PBbqUgQ9IA0ENoIzX/openapi.json
