One CLI and ChatGPT app for ordering across Just Eat, Glovo, and Uber Eats in Spain.
Tell ChatGPT what you need. OrderScout searches anything the enabled platforms make available—restaurant meals, groceries, supermarket products, pharmacy and convenience items, drinks, and household supplies—then compares price, quantity, fees, memberships, ratings, and delivery time. It can prepare the selected basket or cross the guarded purchase boundary only after exact approval.
“Find a healthy, tasty dinner for two under €30. I care more about ratings than speed.”
“Find the cheapest delivered option for everything on this grocery list.”
“Which pharmacy or convenience store can deliver sunscreen fastest?”
“Find the cheapest way to get at least 20 litres of still water. Search all my apps and do not order.”
“I only use Just Eat and Uber Eats, and I have Uber One.”
“Add the first choice to my basket, then open it so I can pay myself.”
OrderScout is an unofficial community project. It is not made, approved, or supported by Just Eat Takeaway.com, Glovo, or Uber.
This is the family-friendly route. You do not need to know any commands after installation.
- Open the ChatGPT desktop app.
- Choose Work or Codex.
- Start a new chat.
- Ask for a meal, groceries, pharmacy products, household supplies, or any other available delivery in normal language.
If OrderScout is not installed, paste this into a Work chat:
Install OrderScout from https://github.com/wachtermar/orderscout. Install its CLI, add its plugin marketplace, install the OrderScout plugin, run its checks, and tell me when to restart ChatGPT. Do not place any order.
The computer needs Node.js 20 or newer once. Restart ChatGPT after installation and begin a new Work chat.
- Just Eat first reuses or refreshes its saved OAuth session. Only when a fresh login is required does it open the official OAuth page; the ChatGPT tool returns immediately, and you simply say when the page has finished.
- Glovo and Uber Eats first check whether any supported Chrome profile already contains a working provider session. OrderScout tries the profiles automatically and saves only a session that passes the provider's live account API. For Glovo it also imports the provider's refresh credential and device identity, so the 20-minute access token renews silently and the rotated login is saved owner-only.
- If no working session exists, ChatGPT opens the official site in normal Chrome. Sign in there, return to ChatGPT, and say, “I finished signing in.” There is no Terminal prompt, cookie copy, or profile-selection question.
- Enter passwords and verification codes only on the official website.
- The same automatic flow is available from the standalone CLI.
Never paste a password, cookie, token, or login URL into chat. ChatGPT's in-app browser does not expose a supported session-export API, so OrderScout does not pretend that a visible in-app sign-in authenticates its CLI. The in-app browser is used only for optional visual review of a CLI-created checkout; search, menus, baskets, quotes, and guarded placement remain CLI operations.
The current plugin is local to ChatGPT Work/Codex on desktop. It is not an ordinary mobile ChatGPT skill yet; a hosted MCP service would be required for phone-only use.
Every provider enabled for your household is searched concurrently on every request. Provider selection lives in account settings, so an agent cannot quietly search a convenient subset. For example, if you enable Just Eat and Uber Eats with Uber One, both are always attempted and Glovo is excluded. Failed sessions are shown in provider coverage instead of being silently omitted.
Just Eat saved addresses may include apartment, building, or door details that its official address autocomplete does not accept. OrderScout first tries the complete saved address and, only when Just Eat rejects that lookup, retries the same official endpoint with street, postcode, and city. This preserves the provider-resolved delivery coordinates without exposing the address or substituting a third-party geocoder.
Glovo renews and persists its own session automatically before its short-lived access token expires. Uber Eats, and a legacy Glovo session imported before this support existed, make one safe automatic attempt to refresh from a verified native Chrome profile. A new Glovo login is required only when the provider revokes or expires the long-lived refresh credential. If a provider still cannot be verified, it remains an explicit failure; OrderScout never falls back to browser search.
| Goal | How it is ranked |
|---|---|
| Cheapest | Current delivered total after fees, discounts, and membership benefits |
| Fastest | Displayed delivery estimate |
| Best | Rating confidence plus request-specific quality signals |
| Value | A balance of total price, ETA, ratings, quantity, and preferences |
Search-card prices are estimates, never the final recommendation price. OrderScout obtains a current checkout quote for the best suitable offer from every provider that returned a match before recommending a winner. Checkout review records the normalized subtotal, every available fee, applied promotions or membership savings, and exact total back into the comparison; exact totals over a hard budget are disqualified.
Scheduled requests use the local Spain timezone and preserve the requested instant through search, basket creation, and checkout. A provider cannot win until both its exact delivered total and the requested delivery window are verified. If a provider cannot configure that slot, OrderScout tries its next suitable result and otherwise reports the comparison as provisional—never as a confirmed winner.
Provider-listed deals are retained: struck-through item prices and savings, percentage discounts, 2-for-1 listings, free delivery, merchant offers, and membership eligibility. Listed deals influence provisional value ranking, while only savings actually shown by checkout affect an exact comparison.
Product and meal discovery is a hybrid LLM + CLI workflow with a deliberate boundary. The CLI executes a fair query plan across up to 24 shopping lines, retrieves provider-native catalogs, normalizes untrusted data, deduplicates it, paginates it, and preserves prices, deals, availability, ratings, and source IDs. Just Eat scans every currently eligible area menu, Glovo loads the complete menu of every discovered merchant, and Uber Eats prioritizes a strict six-call merchant/product discovery budget before bounded full-menu expansion for the strongest returned merchant cards. Fresh menus are cached privately for 15 minutes, identical completed searches are reused for two minutes, and concurrent identical reads are coalesced. A recent cached catalog may cover a transient network, rate-limit, or upstream-server failure, but that provider remains explicitly partial; authentication and permanent provider rejections are never hidden. Just Eat and Glovo do not immediately retry 429 responses. Checkout always revalidates the selected basket, availability, and final price. Failed menus or provider limits are reported as partial coverage and block a confirmed winner. In agent mode static keyword code does not decide what a product or meal means. ChatGPT splits distinct needs into separate shopping lines, chooses broad merchant and catalog queries, inspects normalized candidate pages, assigns a grounded request-fit score on one cross-provider scale, and explicitly selects the same-store bundle that best satisfies each line. If the strongest inspected shop genuinely lacks a line, ChatGPT records that exact missing item instead of inventing a substitute; the resulting partial bundle is visible for comparison but structurally blocked from checkout. Deterministic code then validates quantities, basket compatibility, eligibility, exact totals, and purchase approval. Human CLI users may omit per-line catalog vocabulary; OrderScout then conservatively uses each shopping line's own wording as its fallback query.
Qualitative requests add a separate web-evidence stage. For questions such as “spiciest,” “most authentic,” “tastiest,” or “best-rated outside the apps,” ChatGPT uses its native web search only after the CLI has found current provider candidates. It looks for the exact merchant and locality, and the exact dish when the claim is item-specific; official menus, independent reviews, local press, and outside rating sources are stored as structured claims with direct URLs, rating scale/count, and merchant-match signals. Ambiguous same-name results are rejected. The CLI will not accept a qualitative selection until every requested evidence dimension has either a supported source or an honest not_found research outcome. External evidence never changes provider availability, menu data, promotions, ETA, fees, or price—the provider APIs and exact checkout remain authoritative.
This applies to every agent request, not only the examples in this README. Food, groceries, pharmacy and personal-care items, drinks, household goods, electronics, pet supplies, flowers, and provider-permitted restricted catalogs all use the same candidate workflow. The model may choose different retrieval terms for each shopping line; the CLI never requires one product to match unrelated needs simultaneously.
For pharmacy searches, OrderScout can locate and compare an exact product the user requests; it does not diagnose symptoms, prescribe medication or dosage, or invent medical suitability. Those decisions belong with a pharmacist or clinician.
A preference cannot qualify an unrelated product—ice does not match rice, and a disposable vape is not e-liquid just because its description mentions liquid. Quantity-aware helpers add extra understanding where useful—for example bottle sizes, multipacks, total litres, still versus sparkling, and price per litre for water. Open-ended multi-person meal recommendations prefer explicit varied dish lines or one item sold for sharing; an exact user request such as “three shakshukas” may correctly use quantity three. Breakfast searches require prepared breakfast dishes rather than raw egg packs or a keyword found in an unrelated product. “Healthy” and “tasty” remain transparent ranking signals, not medical or nutritional claims.
Searching, opening a menu, creating a basket, reading checkout, and opening the official checkout page do not place an order.
For age- or identity-restricted goods, OrderScout never bypasses provider eligibility checks. It can discover and compare restricted catalog items, but basket creation is blocked. ChatGPT opens the trusted provider page and the user personally completes the official checkbox or verification. Only after explicit current confirmation does OrderScout unlock that store for the current search; it still does not create or submit an order without the normal later approvals.
Programmatic placement has two locks:
- A dry run returns the current exact order and a short confirmation fingerprint.
- The destructive ChatGPT tool enables placement only inside its fingerprint-confirmed second call. Standalone CLI users must separately set
ORDERSCOUT_ENABLE_ORDER_PLACEMENT=1(JUSTEAT_ENABLE_ORDER_PLACEMENT=1for the retained Just Eat adapter).
The fingerprint changes when the provider, basket, total, or payment request changes. An agent must ask for approval of the exact current order immediately before the second call. Ambiguous submit results are never retried automatically.
In ChatGPT Work, final review happens in the official in-app checkout. OrderScout shows a compact summary and, when it can safely crop private details, a checkout screenshot in chat. The user can change cart contents, address, delivery timing, tip, or saved payment method before approval. Every change invalidates the old quote, image, fingerprint, and approval and requires a fresh review.
Just Eat and Uber Eats expose guarded final-submit adapters. Glovo now has an explicitly experimental guarded adapter: it uses a submit action returned by checkout validation when available and otherwise uses an inferred fallback endpoint. A rejected Glovo request is reported for protocol correction; an ambiguous result is never retried and must be checked in active orders.
| What you want | What to say |
|---|---|
| Configure apps | “I use Glovo and Uber Eats. I have Glovo Prime.” |
| Check login | “Am I logged in to all my delivery apps?” |
| Fast dinner | “Find a well-rated dinner that can arrive fastest.” |
| Grocery list | “Find the cheapest delivered basket for milk, eggs, bananas, and detergent.” |
| Other products | “Find a phone charger I can get tonight.” |
| Pharmacy | “Which pharmacy can deliver SPF 50 sunscreen fastest?” |
| Bulk quantity | “Find at least 12 L of still water at the lowest delivered price.” |
| Dietary choice | “Find three vegetarian dinners under €20.” |
| Compare full totals | “Build temporary baskets and compare every fee. Do not order.” |
| Prepare only | “Put option 1 in my basket, but stop there.” |
| Manual checkout | “Open that same basket on the official website.” |
If an allergy is mentioned, OrderScout stops basket work until the merchant confirms it directly. Menu text is never proof of allergen safety. Pharmacy results describe availability, not medical advice.
npm install --global github:wachtermar/orderscout
codex plugin marketplace add wachtermar/orderscout
codex plugin add orderscout@orderscout-marketplaceRestart ChatGPT desktop after installing the plugin.
For development:
git clone https://github.com/wachtermar/orderscout.git
cd orderscout
npm install
npm link
npm run check
npm run test:liveThe plugin is in plugins/orderscout, and its marketplace is .agents/plugins/marketplace.json.
The normal suite is provider-independent; the privacy-safe production canary and its opt-in draft mode are documented in docs/live-testing.md.
# Account setup
orderscout accounts set --providers justeat,glovo,ubereats \
--memberships '{"glovo":false,"ubereats":true}'
# Official native-browser login
orderscout auth login justeat
# Only if a browser was opened, finish there, then:
orderscout auth complete justeat
orderscout auth login glovo
# Sign in on Glovo, then:
orderscout auth complete glovo
orderscout auth login ubereats
# Sign in and choose the delivery address, then:
orderscout auth complete ubereats
# Direct provider commands
orderscout glovo search "healthy chicken dinner" --at "29603 Marbella"
orderscout glovo menu https://glovoapp.com/es/es/marbella/stores/example
orderscout ubereats search "phone charger"
orderscout ubereats menu <store-uuid>
# One cross-provider search
orderscout recommend "best-rated healthy dinner for two under €30" \
--at "29603 Marbella"
# Agent-guided retrieval: shop first, then product catalog, with separate needs
orderscout search begin "Lost Mary Tappo pods and bottled ice liquid" --agent \
--discovery-queries '["vape","vaper","estanco"]' \
--catalog-queries '["Lost Mary","Tappo","cartucho","líquido","ice","mentol"]' \
--shopping-items '[{"id":"pods","intent":"Lost Mary Tappo prefilled pods"},{"id":"liquid","intent":"bottled vape liquid with ice that is not too sweet"}]'
# The LLM pages and reasons over normalized candidates; this is lexical retrieval, not semantic filtering
orderscout search candidates <search-id> --provider glovo --query "lost mary tappo" --limit 50
orderscout search candidates <search-id> --provider glovo --query "liquido ice" --limit 50
# Qualitative searches can require native-web evidence before selection
orderscout search begin "spiciest dinner in Marbella" --agent \
--external-research required \
--external-dimensions '["spiciness","outside_rating"]'
orderscout search evidence <search-id> --offer-ids '["<candidate-id>"]' --json '{
"status":"found",
"query":"Curry House Marbella phaal spicy review",
"dimensions":["spiciness","outside_rating"],
"identity":{"confidence":"high","matchedSignals":["name","city","menu_item"],"reason":"Same merchant, locality, and dish."},
"sources":[{"url":"https://example.com/review","title":"Review","publisher":"Local guide","sourceType":"independent_review","claims":[{"dimension":"spiciness","summary":"The review identifies the phaal as the hottest curry.","confidence":"high","scope":"item"},{"dimension":"outside_rating","summary":"Rated 4.6/5 from 320 reviews.","confidence":"high","scope":"merchant","rating":{"value":4.6,"scale":5,"count":320}}]}]
}'
# Save one LLM-chosen, same-store bundle locally; this does not create a provider basket
orderscout search select <search-id> --json '[
{"offerId":"<pod-offer>","quantity":1,"forItem":"pods","reason":"Explicit Tappo cartridge","requestFit":98,"confidence":"high","evidence":["Lost Mary Tappo pod"]},
{"offerId":"<liquid-offer>","quantity":1,"forItem":"liquid","reason":"Bottled mint-ice liquid rather than a disposable","requestFit":92,"confidence":"high","evidence":["bottled menthol ice e-liquid"]}
]'
# An honest best partial basket names missing lines and is automatically blocked from checkout
orderscout search select <search-id> --json '[
{"offerId":"<bread-offer>","quantity":1,"forItem":"bread","reason":"Exact bread match","requestFit":100,"confidence":"high","evidence":["Fresh bread"]}
]' --missing-items '[
{"forItem":"ground-coriander","quantity":1,"reason":"The complete store catalog contained fresh cilantro but no ground coriander.","evidence":["No ground coriander candidate in the inspected merchant catalog"]}
]'
# Explicitly close providers with no suitable complete bundle, then quote every selected provider at once
orderscout search review <search-id> ubereats --disposition inspected_no_suitable_match --reason "No matching bottled liquid after all candidate pages"
orderscout comparison quote <search-id>
# Only after the user explicitly completes the provider's legal-age control
orderscout eligibility confirm <search-id> <offer-id> --confirmed true
# Prepare, create, and quote a selected offer
orderscout basket prepare <search-id> <offer-id>
orderscout basket create <search-id> <offer-id>
orderscout basket checkout <search-id> <offer-id>
# Open the same server-side basket for manual review
orderscout basket open <search-id> <offer-id>
# Dry-run the final purchase boundary
orderscout order place <search-id> <offer-id>basket prepare is a local payload preview. basket create creates the provider draft, preserving every distinct meal line. basket checkout uses the provider's current checkout contract and automatically records normalized exact pricing. Glovo refuses to append comparison items when that store already has a non-empty unrelated basket.
The original Just Eat-specific commands remain available under orderscout justeat ... and the legacy justeat executable.
| Capability | Just Eat | Glovo | Uber Eats |
|---|---|---|---|
| Login/status/logout | OAuth + API | Native Chrome session + API | Native Chrome session + API |
| Search and menus | Direct menus | Merchant → catalog | Direct menus |
| Saved account/address context | Direct | Direct | Session-backed direct API |
| Server-side basket | Direct | Direct | Direct |
| Checkout quote | Direct | Direct validation | Direct |
| Open basket in official site | Yes | Verify selected cart | Yes |
| Guarded programmatic final submit | Yes | Experimental | Yes |
Private state lives under ~/.config/orderscout-cli/ with owner-only permissions. Just Eat retains its existing state under ~/.config/justeat-es-cli/. Never publish these directories. Raw provider responses may contain personal information.
OrderScout is experimental pre-1.0 software built against private consumer APIs that may change without notice. Tests use synthetic responses and never call a final payment endpoint. Live smoke checks are read-only.
npm run check
npm run test:matrix
npm run test:coverage
npm run pack:checktest:matrix runs the generated English/Spanish request matrix without provider traffic. The full suite also runs 456 realistic food, grocery, pharmacy, drink, restricted, scheduled, and multi-line requests through all three selected-and-exact-quoted provider paths, alongside more than 1,800 language combinations plus paging, bundle, pricing, promotion, schedule, eligibility, and failure invariants. See the query-matrix documentation for scope and known limits. Live smoke checks deliberately use a small, paced set of read-only requests because provider rate limits are real production behavior, not something the test suite should bypass.
The design takes operational lessons from steipete/ordercli and the Domino's Printing Press CLI. The implementation is original; see third-party notices.
MIT