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

Export Homebrew install-on-request rankings, counts and share. Track rank changes and formulae entering or leaving your selected window.

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

21 hours ago

Last modified

Share

Export Homebrew formula rankings, install counts and share from the official Formulae JSON API. Repeat the same analytics window to track rank changes and formulae entering or leaving it. Install counts and share are included as observations; changes to those two values do not trigger events.

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.

Homebrew does not provide historical rankings through this endpoint. Each row records the analytics window at scraped_at; monitoring history starts with your first successful monitor run.

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

Choose an export, a recurring ranking check, or a watchlist of named formulae.

  • 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.

  • Elixir, Erlang and Gleam: Hex.pm Package Rankings tracks the Hex.pm top-N by 90-day downloads and rank changes between runs.
  • Dart and Flutter: pub.dev Package Rankings tracks pub.dev downloads, likes and pub points for selected packages.
  • AI models: Hugging Face Model Rankings tracks a Hugging Face task top-N or a named model watchlist for rank, license and gating changes.

Each Actor runs and charges separately. This Actor does not call them.

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).

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.
  • EXITED tombstones are kept 180 days, at most 20 000 per query. After prune, a very old return may classify as NEW.
  • Use 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.

Source: the official Formulae API. The Actor reads public package metadata and anonymous aggregate analytics.

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. Run it through MCP with your own Apify account and run budget.

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.