# Pixelfed Creator Post Monitor - Public Feeds and Changes

Monitor opt-in public Pixelfed creator feeds for captions, media links and saved post changes. Filter literal topics and dates. Bounded visible feed windows; no login or media downloads.

Canonical product page: https://mayd-it.com/data-tools/actors/pixelfed-creator-post-monitor/
Public Actor: https://apify.com/maydit/pixelfed-creator-post-monitor

## Example input

```json
{
  "feedUrls": [
    "https://pixelfed.social/users/pixelfed.atom"
  ],
  "maxPostsPerFeed": 5,
  "maxResults": 5
}
```

## Full guide

![Keep a public photo-post log — illustrative workflow](https://api.apify.com/v2/key-value-stores/YGxD9JRpduom8Q5Zd/records/pixelfed-creator-post-monitor-2e61b9219734.png?signature=1SmmAe5AOaqNbv4xcf6iM)

[Open this Actor in Console](https://console.apify.com/actors/93Kv9KcqIm9cAHTGM/input) · [Try a small run](#try-a-small-run) · [Cost](#cost)

**Mayd-It · Public photo feeds**

Turn opted-in Pixelfed creator feeds into a publishing log. Keep captions, source links and media metadata together, and notice changes visible in later feed responses.

**Source scope:** Explicit public Atom feeds with a small publisher-controlled window. Media links are returned; images and videos are not downloaded.

## What you get

- A distinct row for each public photo or photo-album post.
- Caption text, hashtags, source timestamps and supplied media-link metadata.
- Literal keyword evidence and optional saved caption or media changes.

## Try a small run

Copy this exact input into the Actor’s JSON input editor, then run it.

```json
{
  "feedUrls": [
    "https://pixelfed.social/users/pixelfed.atom"
  ],
  "maxPostsPerFeed": 5,
  "maxResults": 5
}
```

This example inspects up to five visible posts from the official Pixelfed creator feed. No account, API key or proxy is needed for this source. Open the dataset for rows and `SUMMARY` for actual coverage. `{}` inspects up to ten visible posts from the same feed, with a saved-result cap of 20; omitted or empty `feedUrls` and Console prefill use that feed. Comparison is off by default.


## Understand your run

Open **Run report** in the run’s Output tab for saved-record counts, reported source issues and limits, and suggested next steps. Use **CSV export** to take the saved results into a spreadsheet. The existing JSON results and detailed machine-readable summary remain available.

The report reflects this run’s recorded coverage. A successful run or a saved result does not establish that every possible source record was collected.

## Cost

**FREE / BRONZE: $0.002 per saved observation ($2 per 1,000).** SILVER: $1.60 per 1,000. GOLD / PLATINUM / DIAMOND: $1.20 per 1,000.

The Actor Start event is **$0.00005 per charged start unit**, with one unit per GB of Actor memory and a minimum of one. The Pricing tab shows the rate for your Apify tier. New, changed and ordinarily saved unchanged observations use the same result rate. Skipped unchanged rows, rejected events, duplicates and error diagnostics are not paid result rows. Use `onlyChanges` for repeated monitoring after establishing history.

## A real result

Selected fields from a recorded run on **10 October 2026**. This is an example of the output shape; source content and counters can change.

```json
{
  "creatorUsername": "pixelfed",
  "caption": "Stories. Shipping soon! #pixelfed",
  "updatedAt": "2026-09-21T15:09:22.000Z",
  "mediaCount": 3,
  "hashtags": [
    "pixelfed"
  ],
  "comparisonStatus": "not_requested"
}
```

`updatedAt` is the source Atom field. On the official template it contains the creation time, so it is not a reliable last-edit timestamp. `mediaCount` counts supplied links.

## More examples

### Pixelfed founder public photo posts

Read the founder’s opted-in public photo feed.

```json
{
  "feedUrls": [
    "https://pixelfed.social/users/dansup.atom"
  ],
  "maxPostsPerFeed": 5,
  "maxResults": 5
}
```

### Pixelfed creator topic watchlist

Inspect two creator feeds for the literal word `pixelfed`. These examples keep history off; add `onlyChanges: true` and a chosen `snapshotName` for a recurring monitor.

```json
{
  "feedUrls": [
    "https://pixelfed.social/users/pixelfed.atom",
    "https://pixelfed.social/users/dansup.atom"
  ],
  "keywords": [
    "pixelfed"
  ],
  "maxPostsPerFeed": 10,
  "maxResults": 20
}
```

---

Feed URLs must have the form `https://instance.example/users/username.atom`. Supply at most 20 explicit creators. Arbitrary RSS feeds, profile-page scraping and redirects to a different creator are unsupported.

## What the public source actually exposes

Pixelfed's [official controller](https://github.com/pixelfed/pixelfed/blob/dev/app/Http/Controllers/ProfileController.php) requires enabled Atom feeds, an unlocked local profile, and the creator's `show_atom` setting. Its current implementation selects the newest **10 public photo or photo-album posts** and caches a feed for **four hours**. Instances can run different versions or disable feeds. This Actor validates the expected feed, creator and post structure.

The feed window is not a complete archive. There is no pagination, whole-network search, private-content access, follower harvesting, image/video download, or inferred deletion detection. Increasing `maxPostsPerFeed` cannot expose history the publisher omits. Polling more often than the source cache refresh can repeatedly return the same content.

The [official Atom template](https://github.com/pixelfed/pixelfed/blob/dev/resources/views/atom/user.blade.php) currently places `created_at` in `<updated>`. Accordingly, **`updatedAt` is the literal Atom field, not a reliable last-edit timestamp**. The Actor compares caption and media snapshots to notice changes that become visible in later feed responses. `publishedAt` is null on the tested flagship feeds; it is populated only if a feed explicitly includes an Atom `<published>` timestamp.

## Filters and limits

| Input | Behavior |
|---|---|
| `feedUrls` | Up to 20 public HTTPS creator feed URLs; omitted/empty uses the official profile. |
| `keywords` | Up to 30 case-insensitive literal phrases, OR within the list, matched against title or caption. Empty matches all. |
| `updatedFrom`, `updatedTo` | Inclusive real `YYYY-MM-DD` UTC dates applied to Atom `updated`; these are not edit-date filters. |
| `maxPostsPerFeed` | Default 10, range 1–100; take the publisher's first usable entries **before** filters. |
| `maxResults` | Default 20, range 1–1,000; maximum confirmed saved rows across all feeds. |
| `maxRunSeconds` | Default 240, range 30–3,600; every network operation fits this and the platform deadline minus 25 seconds. |

Populated date and keyword filters combine with AND. Literal match evidence includes the matching field, phrase and excerpt. No semantic topic inference is performed. Output follows input feed order and then publisher entry order; it is not a global time sort. Duplicate feed URLs are fetched once and duplicate canonical post identities are saved once.

Captions are decoded into plain text and limited to 30,000 characters, with `captionTruncated` and a hash of the full decoded caption. Keyword matching inspects only the returned text. Media links are metadata only; nothing at those URLs is downloaded. Alt text and MIME types are null if the feed does not supply them. Email/contact elements and profile biographies are not collected.

## Output and history

`postId` is the canonical public post URL, including instance and creator; numeric IDs alone are not assumed globally unique. Each saved row includes:

- `postId`, `url`, `creatorUsername`, `creatorUrl`, `instanceUrl`, `feedUrl`, `feedTitle`, `feedUpdatedAt`;
- `title`, `caption`, `captionHash`, `captionTruncated`, `updatedAt`, optional `publishedAt`;
- `media` entries containing `url`, optional `mimeType` and optional `altText`; `mediaCount` and literal caption `hashtags`;
- `matchedKeywords`, `contentHash`, `observedAt`, and comparison fields.

Set `comparePrevious: true` to compare against a named key-value store. Set `onlyChanges: true` to enable comparison and skip unchanged observations. On the **first run**, every matching observation is emitted as `new`, and the run warns that it is establishing history. Here `new` means new to that saved history, not necessarily recently published. A later no-change run warns and succeeds with zero rows.

`comparisonStatus` is `not_requested`, `new`, `changed` or `unchanged`. `changedFields`, `previous` and `previousObservedAt` explain the comparison. The snapshot includes title, returned caption, full caption hash, truncation flag, source timestamps, ordered media metadata and sorted literal hashtags. Feed refresh timestamps and the Actor's observation time do not trigger post changes. Media URL changes do count, including an upstream URL rewrite.

History is scoped by `snapshotName`, the sorted feed set, literal filters and `maxPostsPerFeed`. Feed order and `maxResults` do not create a separate namespace. **Use one concurrent writer per scope.** An optimistic read-back detects an overlapping update, but the key-value store does not provide an atomic transaction. Choose a new snapshot name to reset or replace incompatible history.

Only confirmed saved observations advance history. Failed or spending-limit-rejected rows do not. An incomplete run can preserve accepted observations without establishing removals or a complete baseline. The store retains up to 20,000 identities per scope. `SUMMARY.historyUpdated` confirms whether a history commit occurred.

## Coverage and failures

The default key-value store's `SUMMARY` reports `rowsSaved`, `rowsObserved`, `filtered`, `unchangedSkipped`, `sourceCoverage`, `sourcesNotReached`, `failedSources`, `historyUpdated` and limit flags. `status: "ok"` means the requested bounded check completed, not that the full creator archive was covered. An ordinary requested result cap is not an error.

Time, source and spending interruptions set `incomplete: true`. Source errors are recorded in SUMMARY/logs, never as paid dataset rows. If all requested sources fail before any usable observation, the run fails. A valid feed with no visible posts or no matching filters warns and succeeds. A run stopped before its first save solely by a spending cap warns without pretending to have collected posts.

Requests honor instance robots rules, including matching `Crawl-delay`, across retries and redirects. A delay that cannot fit the remaining deadline stops that source. HTML masquerading as `robots.txt`, authentication blocks and unexpected feed shapes are rejected. Public DNS validation, pinned addresses and redirect checks prevent private-network access. XML DTDs/entities are rejected, and no linked media or external XML resources are fetched.

## Troubleshooting and support

| If you see… | Check this |
| --- | --- |
| A creator feed fails | Confirm that the creator has enabled Atom and that the profile is public and unlocked. A disabled feed does not mean the creator has no posts. |
| The same posts keep returning | The official feed can be cached for four hours and exposes a short window. A larger limit cannot recover omitted history. |
| A post appears unchanged | Compare the caption and media snapshot. The Atom timestamp alone does not establish whether a post was edited. |

For help, open an Actor issue or contact **bmay@mayd-it.com**. Include the run ID, selected sources and the relevant `SUMMARY` message. Do not send credentials. This Actor is independent of the platform.

Public availability does not transfer copyright or grant permission to republish creators’ images. This Actor returns public feed metadata and media links. Use the source information within the applicable instance and creator terms. It does not download media or build a training dataset.
