DoorDash

get-menu

doordash.com
InstallationInstalls just this skill for your agent
Side effectread
Authnone (session optional)
Needsevaluate
Summary

Read a DoorDash store's full menu (categories, items, prices) plus store info by store id.

Params
{"storeId":"string (DoorDash store id, digits only, e.g. \"26013\"; the `id` returned by doordash-search-stores)"}
Returns
{"store":"{ id, name, cuisine, priceRange, rating, numRatings, deliveryTime, deliveryFee, dashpass, offersDelivery, offersPickup, address, phone, website, currency, status }","categoryCount":"int","count":"int (total items)","categories":"array of { name, description, itemCount, items:[{ id, name, description, price, priceAmount, strikethroughPrice, rating, callout, image }] }"}
SKILL.md57 lines

doordash-get-menu

Reads a store's whole menu from its storeId. Each item's id is what doordash-add-to-cart takes as its itemId, chains straight off doordash-search-stores. Resolves in a single bridge call. The extractor lives as text in the site's localStorage (key doordash-get-menu) and is rebuilt on each call with synchronous eval. It is stored once and then persists across navigation and browser restarts, so on every run except the first it is already there.

Default action: just call (step 1). The call itself reports NEEDS_STORE when the extractor is missing or out of date, only then do you store it (step 2) and call again.

Versioning. The stored extractor is gated by VER (must match the version in the frontmatter above). Both snippets carry VER = "1", keep them in sync with the frontmatter. When evaluate.js changes, bump version and VER in both snippets: the next call sees the mismatch, returns NEEDS_STORE, and re-stores automatically. Storage stays at two keys (doordash-get-menu and doordash-get-menu:ver), overwritten each store, versions never accumulate.

1. Call (do this every run, params only, single bridge call)

await (() => {
  const KEY = "doordash-get-menu", VER = "1";
  const s = localStorage.getItem(KEY);
  if (!s || localStorage.getItem(KEY + ":ver") !== VER) return 'NEEDS_STORE';
  const fn = eval('(' + s + ')');
  return fn(document, { storeId: "26013" });
})()

Returns the store info plus every category and item. If it returns the string 'NEEDS_STORE', the extractor is missing or stale in this browser → do step 2 once, then run this exact call again.

Run this snippet verbatim. Never add an await before the eval, only the outer await is allowed.

Any doordash.com tab works, the extractor fetches everything itself and never reads the open page, so no navigation is needed. The tab only supplies the origin and session.

2. Store (only when step 1 returned NEEDS_STORE; persists until localStorage is cleared)

From any doordash.com tab, evaluate the following with the bridge, replacing <FN> with the contents of evaluate.js (the ( async (root, params) => { ... } ) function). Keep VER equal to the call snippet's:

(() => {
  const KEY = "doordash-get-menu", VER = "1";
  const fn = (<FN>);
  localStorage.setItem(KEY, String(fn));
  localStorage.setItem(KEY + ":ver", VER);
  return 'stored';
})()

Returns "stored". The extractor passes through the model only here, once. Then go back to step 1.

Notes

The menu is parsed out of the page's Next.js RSC flight payload, not the DOM, one fetch returns the whole menu (100+ items is normal) with no pagination.

Errors

  • NEEDS_STORE → extractor missing or version-mismatched in this browser; run step 2 once, then retry step 1.
  • flight_not_found → the store page carried no RSC payload; DoorDash changed its rendering.
  • menu_not_found → the storeId is wrong, or the store is unavailable at the session address.

Success assertion

{ "type": "json", "jsonPath": "count" }
get-menu: a DoorDash skill for AI browsing agents · browser-memory