Restaurant Menu Item-Price History
Pricing
from $10.00 / 1,000 results
Restaurant Menu Item-Price History
Track restaurant menu item prices over time. Records each dish's price from public schema.org menu data into an append-only price-history ledger, and computes a menu-price inflation index — the price history a one-shot scraper can't reconstruct.
Pricing
from $10.00 / 1,000 results
Rating
0.0
(0)
Developer
David Liu
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
5 days ago
Last modified
Categories
Share
Restaurant Menu Item-Price History (Keystone N1 probe)
Probe-grade v0 of Keystone candidate N1 / GATE C1: a niche time-series scraper that extracts per-item restaurant menu prices and appends them to a never-delete, append-only history ledger. The accumulating dated price series is the product: a fresh, memoryless scraper can only see today, so the months of dated history retained here are the practical edge — you had to have been watching the source over time to have it.
Integrity claim (what is provable today). The ledger is append-only and
tamper-evident to the operator: it is never rewritten or deleted, and
fingerprint() is a self-computed SHA-256 over the file so the operator can
detect after-the-fact mutation of their own store. It is not, on its own,
cryptographically un-backfillable — a plain self-computed hash does not stop
the operator from recomputing it over back-dated rows. Provable un-backfillable
integrity (Ed25519 hash-chain + Merkle roots + external anchoring, carried
from the Deadman pattern) is a deferred before-scale upgrade; until it ships
the public copy claims only "append-only + tamper-evident," never "un-forgeable"
or "un-backfillable." (Claim only what is provable — the Deadman discipline.)
Status: feature branch only, probe-grade. Not merged, not deployed, not published to Apify. The human publishes. See
CHANGE_NOTE.md.
What it does
- Scrape a small, config-driven seed list of restaurants via a pluggable
source adapter (default real source: schema.org
MenuJSON-LD on each restaurant's own public page). - Append each observation to an append-only JSONL ledger, keyed by{source, restaurant_id, item_id, name, price, currency, captured_at}
(source, restaurant_id, item_id, date) -> price, idempotent (re-running the same day is a no-op; a price change on a later day appends a new dated row; nothing is ever deleted). - Query the retained history:
priceHistory(item/restaurant over time)and a menu-price index aggregate (mean/median % price change by cuisine or city over a window).
Layout
| Path | Purpose |
|---|---|
.actor/actor.json | Apify Actor definition |
.actor/input_schema.json | Actor input schema (source, seeds, flags) |
.actor/dataset_schema.json | Dataset output shape |
Dockerfile | Apify Node image; installs apify SDK for the deployed Actor |
src/ledger.js | The product — append-only, idempotent, never-delete ledger |
src/query.js | Price-history + menu-price-index queries |
src/scrape.js | Source-adapter dispatcher + polite runner |
src/adapters/jsonld.js | Default real source: schema.org Menu JSON-LD |
src/adapters/fixture.js | No-network adapter (selftest + safe default) |
src/config.js | Gating flags (default-OFF where they gate behavior) |
src/main.js | Actor entry (real run). Apify SDK loaded softly; runs standalone too |
test/selftest.js | State-neutral, no-network selftest |
test/fixtures/ | Canned menu payloads + a menu-page HTML fixture |
seeds/restaurants.example.json | Example seed list |
Run the selftest (no network, mutates no committed state)
$node test/selftest.js # or: npm run selftest
It validates append / dedupe / change / never-delete / query / parser logic on fixtures, and hashes the committed project tree before and after to prove it mutates nothing. Ledger writes go to an OS temp dir that is cleaned up.
Run a real scrape (manual — NOT part of the selftest)
# 1) Build a small seed list of restaurant menu-page URLs (see seeds/).# 2) Provide it via input.json or Actor input:cat > input.json <<'JSON'{ "source": "jsonld","seeds": [ { "restaurant_id": "some-place", "url": "https://…/menu", "cuisine": "Italian", "city": "NYC" } ],"ledgerPath": "./data/price-history.jsonl" }JSONnode src/main.js
Default source is fixture (no network). A real network run must
explicitly opt into jsonld. Politeness (delay + normal UA) is enforced by
src/scrape.js. No login, no PII, only the exact seed URLs.
Deferred / follow-ups
See CHANGE_NOTE.md for the source + ToS read and the deferred hardening list
(robots.txt preflight, anti-bot resilience, additional adapters, SQLite backend,
signed/Merkle ledger integrity carried from the Deadman pattern).