Homebrew Formula Install Rankings & Change Monitor avatar

Homebrew Formula Install Rankings & Change Monitor

Pricing

from $0.60 / 1,000 formula results

Go to Apify Store
Homebrew Formula Install Rankings & Change Monitor

Homebrew Formula Install Rankings & Change Monitor

Monitor Homebrew formula install-on-request rankings. Track rank, install share and new/exited formulae via the official Formulae JSON API.

Pricing

from $0.60 / 1,000 formula results

Rating

0.0

(0)

Developer

Vadim Bezrukov

Vadim Bezrukov

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

3 days ago

Last modified

Share

See which Homebrew formulae people are installing on purpose, whether rank or install share moved since your last successful check, and whether a watched CLI tool entered or left the window. The Actor reads the official Formulae JSON API. It does not scrape formulae.brew.sh HTML, download the 31 MiB formula catalog, or collect cask analytics.

Paste the prefill below, run once, and you get the current top-20 install-on-request formulae plus one query_status row. Next week, switch the same metric and period to monitor + changesOnly under a stable stateNamespace.

This is not a claim that Homebrew Store search demand is measured, and it is not a quality comparison with other Store scrapers. Homebrew does not provide a native install-rank history; each row is an observation at scraped_at for that analytics window.

Choose your workflow

GoalSettingsWhat you get
Export today's top-N on-request rankingsnapshot + allOne formula_observation per formula, all BASELINE
Re-check the same window next weekmonitor + changesOnlyNEW, RANK_UP, RANK_DOWN, EXITED, REAPPEARED
Watch named formulaewatchlistObservations only for those names; rank comes from the full window

These are the three jobs the Actor is built for. Saved Console examples use the same inputs; they stay unpublished until you publish each Task separately.

  • Export top formulae for install-on-request, default 30-day window. First run writes BASELINE rows and one query_status.
  • Monitor rank changes on the same query later. Keep stateNamespace stable. Later runs return NEW, RANK_UP, RANK_DOWN, EXITED or REAPPEARED. Daily install-count drift is not a change.
  • Watch named formulae such as gh, wget and ripgrep. A name missing from a populated analytics window is delivered as an unranked SUCCESS row (rank null), not NOT_FOUND.

BASELINE means "this is the first successful ranking we stored for this query". It does not mean the formula was created today.

Quick start

{
"mode": "snapshot",
"metric": "installOnRequest",
"period": "30d",
"topN": 20
}

On the 2026-09-11 probe, rank 1 for install-on-request 30d was gh. Then schedule the same window:

{
"mode": "monitor",
"outputMode": "changesOnly",
"stateNamespace": "onrequest-30d",
"metric": "installOnRequest",
"period": "30d",
"topN": 20
}

Keep stateNamespace stable for a given watch. Snapshot mode does not read or write history. snapshot + changesOnly is rejected before any Homebrew request. Changing metric, period, or (for top-N queries) topN starts a new query_key and a new baseline. A named watchlist is keyed without topN, so changing topN does not reset that watch.

A watchlist accepts gh or https://formulae.brew.sh/formula/gh. Other hosts are INVALID_INPUT without a fetch. Rank is the analytics number, even when it is greater than topN. A watchlist name missing from a populated JSON window is delivered as an unranked SUCCESS observation (rank null), a candidate for EXITED only after it was previously ranked, not NOT_FOUND. The query stays SUCCESS when analytics returned a populated window; NO_RESULTS is only a verified items: []. Optional per-formula metadata HTTP 404 is item-level NOT_FOUND with ranking fields still filled from analytics.

Formulae JSON API vs this Actor API

  • Formulae JSON API: GET https://formulae.brew.sh/api/analytics/install-on-request/{period}.json and, if you turn metadata on, GET https://formulae.brew.sh/api/formula/{name}.json. Public JSON, no token.
  • Actor API: Apify input, Dataset rows (formula_observation, query_status, run_summary), and optional last-good state in this Actor's key-value store.

Default metric is install-on-request, not install-all. The install metric counts dependency installs; on 2026-09-11 its rank 1 was ca-certificates.

The Actor never requests /api/formula.json. Analytics ids may be tap-qualified (user/tap/formula); those rows keep that identity and do not collapse onto a core formula of the same short name.

What changed, and what did not

Monitor diffs last successful state against current successful state.

  • First successful monitor, including changesOnly, emits BASELINE.
  • A new id after that is NEW. Rank moves are RANK_UP / RANK_DOWN.
  • installs and percent are not compared. Homebrew rebuilds each rolling window daily, so those numbers move on almost every formula between any two runs (on 2026-09-12 all of the top 5 had new counts and identical ranks). They stay on every row as observation data; a row whose rank did not move is UNCHANGED and, in changesOnly, not delivered. Use outputMode=all if you want the count series itself. UPDATED remains in the schema for rows written before 2026-09-13 and is no longer emitted.
  • An id missing from two different sequential successful complete windows becomes EXITED. The first miss is pending_exits only. A transport error, OUTPUT_LIMIT, or mass-removal guard does not advance that counter.
  • EXITED means "not in this query's successful top-N / watchlist response". It does not mean the formula was deleted from Homebrew core.
  • If a successful top-N window keeps under 50% of the previous ids at the same topN, the query is PARTIAL (mass-removal guard). Named watchlists skip that guard: every missing id is a pending/EXITED candidate. Pending exits are not applied on mass-removal.
  • A PARTIAL parse window (some selected rows unparseable) still classifies the parsed rows against the last good state, but counts no exits and does not store the snapshot. The next SUCCESS window repeats those events with the same event_id; drop batches whose query_status is not SUCCESS.
  • Broken stored state is STATE_INCOMPATIBLE for that query, not a silent new baseline. The run fails after writing query_status and run_summary.

Homebrew count values arrive as comma-formatted strings ("251,930"). A broken count is FAILED for that row, never silently 0.

Failure semantics

NO_RESULTS is a verified analytics items: []. It is never a transport failure, and it is not "this watchlist id is unranked in a populated window". HTML when JSON was expected, truncated JSON, HTTP 5xx, 429 after retry, or a body over 8 MiB (SOURCE_LIMIT) are FAILED. The Actor run then fails (SOURCE_FAILED) after writing query_status and run_summary. Do not treat Apify SUCCEEDED as proof the window was usable: automation should key off query_status. Missing formula metadata is HTML 404 from GitHub Pages; that is item-level NOT_FOUND for that formula (rank still comes from analytics), not an empty ranking. A metadata request that fails after retries is item-level PARTIAL with error.code=METADATA_FAILED and null desc / homepage / license; the window stays SUCCESS, state advances, and that row is not charged. query_status carries not_found_count and metadata_failed_count. This holds for top-N and watchlist queries alike, so a formula that was removed from core but is still in the analytics window cannot stall a watch. Invalid input writes one query_status (INVALID_INPUT) and a run_summary (INVALID_INPUT), then fails the run before any Homebrew request. A spend cap that cannot cover the window writes NOT_PROCESSED and does not fetch Homebrew.

maxFormulaRows never truncates a window: if the formula rows do not fit, you get PARTIAL / OUTPUT_LIMIT and the previous state is kept. A cap below topN (or below the watchlist length) is INVALID_INPUT before any request. Default is 400 so a full top-200 window plus EXITED rows still fits.

Pricing

The Store Pricing tab is authoritative. Current pay-per-event rates:

EventWhen it is chargedFREE / BRONZE
apify-actor-startPlatform start; one event at the default 512 MB. The Actor never emits it.$0.00005
formula-resultEach delivered SUCCESS formula row in snapshot. In monitor, only NEW / RANK_* / EXITED / REAPPEARED; count drift is never charged.$0.001
window-checkMonitor mode, fully delivered window, including NO_RESULTS and zero-change. Not charged for PARTIAL or FAILED.$0.01

formula-result is $0.0008 on SILVER and $0.0006 on GOLD+. Platform usage is included, not passed through. apify-default-dataset-item is off: enabling it would double-bill every Dataset row.

A run cap must cover start plus the events: $0.02 is not enough for the sample top-20, and $0.01 is not enough for a quiet monitor. The minimum run cap is $0.021 so the Store prefill can finish. Snapshot of 20 formulae → 1 × $0.00005 start + 20 × $0.001 = $0.02005. Quiet or first monitor of the same top-20 → start + $0.01 window-check = $0.01005 and $0 change rows. A weekly top-20 monitor with, say, three rank moves → $0.01005 + 3 × $0.001 = $0.01305; the worst case is every row moving, $0.03005. Retries, FAILED and PARTIAL are not charged as formula-result or window-check (the platform still charges start).

Private cloud measurement on 2026-09-11 (build 0.1.4, 512 MB): snapshot of 20 formulae → 1 × $0.00005 start + 20 × $0.001 = $0.02005 (contribution margin ~78%). Quiet or first monitor of the same top-20 → start + $0.01 window-check = $0.01005 (~75%). A run cap must cover start plus the events: $0.02 is not enough for the sample top-20. The minimum run cap is $0.021 so the Store prefill can finish.

Limitations

  • Cask-install analytics are out of scope.
  • There is no native Homebrew history comparable to storing yesterday's JSON yourself. curl of the same public endpoint remains free.
  • Store search for this keyword family was in an EMPTY band at selection time. Do not read this README as evidence of measured demand.
  • EXITED tombstones are kept 180 days, at most 20 000 per query. After prune, a very old return may classify as NEW.
  • MVP assumes one writer per stateNamespace and sequential runs. There is no distributed lock.
  • Optional metadata GETs are sequential. Metadata fields are omitted from the ranking fingerprint and never decide the window status. Tap-qualified analytics ids (user/tap/formula) have no Formulae /api/formula/{name}.json page; metadata stays null for those rows.

Legal review on 2026-09-11: https://formulae.brew.sh/robots.txt has a Sitemap and no Disallow. Analytics are anonymous aggregates. Re-read robots and the Formulae API docs before Store publication; a later ban is a stop, not something to bypass.

Use from AI agents with MCP

Connect the public Actor directly at https://mcp.apify.com?tools=automa-flow/homebrew-formula-install-rankings-monitor. Ask the agent to keep mode: monitor and outputMode: changesOnly on repeat runs, to treat NO_RESULTS as a verified empty window, not a source failure, and to treat FAILED / a failed run as an unusable Homebrew check. This Actor is not targeted for MCP payment; do not treat that URL as agentic billing readiness.

Schedule and webhook example

This is a copy-paste illustration, not a hosted integration promise. Homebrew rebuilds the window daily; weekly is a sensible cadence for rank moves.

Create the schedule (Console: Schedules, or the API; replace <ACTOR_ID> with this Actor's ID and keep stateNamespace stable):

{
"name": "homebrew-onrequest-30d-weekly",
"cronExpression": "0 7 * * MON",
"timezone": "UTC",
"isEnabled": true,
"actions": [
{
"type": "RUN_ACTOR",
"actorId": "<ACTOR_ID>",
"runInput": {
"body": "{\"mode\":\"monitor\",\"outputMode\":\"changesOnly\",\"stateNamespace\":\"onrequest-30d\",\"metric\":\"installOnRequest\",\"period\":\"30d\",\"topN\":20}",
"contentType": "application/json; charset=utf-8"
},
"runOptions": { "build": "latest", "timeoutSecs": 180, "memoryMbytes": 512, "maxTotalChargeUsd": 0.12 }
}
]
}

Then add a webhook on ACTOR.RUN.SUCCEEDED that posts the run to n8n / Make / your endpoint:

{
"eventTypes": ["ACTOR.RUN.SUCCEEDED", "ACTOR.RUN.FAILED"],
"condition": { "actorId": "<ACTOR_ID>" },
"requestUrl": "https://your-endpoint.example/homebrew",
"payloadTemplate": "{\"runId\":{{resource.id}},\"status\":{{resource.status}},\"datasetId\":{{resource.defaultDatasetId}}}"
}

In the receiver:

  1. Fetch GET /v2/datasets/{datasetId}/items?clean=true.
  2. Drop the batch if the query_status row is not SUCCESS (including PARTIAL parse windows) or the run status is FAILED.
  3. Keep rows where record_type=formula_observation and change_type is one of NEW, RANK_UP, RANK_DOWN, EXITED, REAPPEARED. Each row already carries formula, rank, rank_previous, source_url and event_id, so it can be posted as an alert as-is; dedupe on event_id.
  4. Open source_url for the human check. Do not read EXITED as "deleted from core".

Protocol notes

User-Agent:

automa-flow-homebrew-formula-install-rankings-monitor/0.1 (+https://apify.com/automa-flow)
. Origin is fixed to https://formulae.brew.sh. Redirects off that host fail the window. Analytics timeout 30 s; optional formula metadata timeout 20 s. Uncompressed bodies over 8 MiB are FAILED / SOURCE_LIMIT.