Too Good To Go Scraper icon

Too Good To Go Scraper

Scrape Too Good To Go (TGTG) stores and surprise bags by location or item: price, value, savings, quantity, pickup windows, ratings, favorites and…

Start using this actor on Apify ↗Need a custom scraper?Contact us ↗

Too Good To Go Scraper at a glance

Too Good To Go Scraper is a ready-to-run Apify actor from abotapi for collecting web data. Its documented output includes kind, itemid, url, title and itemname, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $2.50 per 1,000 results on the Apify Free plan and from $1.80 on paid plans, with smaller per-run or optional feature charges listed on Apify.

Runs on
Apify cloud: console, API, schedules and integrations
Data type
Web data
Pricing
$2.50 per 1,000 results (Free plan), from $1.80 on paid plans
Output
Documented below · JSON, CSV, Excel
Inputs
26 options

Scrape Too Good To Go (TGTG) stores and surprise bags by location or item: price, value, savings, quantity, pickup windows, ratings, favorites and store details. Availability monitoring (NEW, UPDATED, REAPPEARED, EXPIRED), detail enrichment, incremental runs, MCP export.

What Too Good To Go Scraper: Stores, Surprise Bags & Availability can do

  • Real mobile-app data. Bag listings carry exact quantity available, pickup window, price and value in one record, not a scraped map screenshot.
  • Location search around one or many points. Each location gets an even share of the item budget, so a multi-city run stays balanced instead of one city eating the whole budget.
  • Item mode for direct reads. Paste bag links or numeric ids for a fully enriched single-item record; search filters are ignored in this mode since each item is read directly.
  • Availability monitoring. Recurring runs classify every record NEW, UPDATED, UNCHANGED, REAPPEARED or EXPIRED, with per-campaign state you can name or share across runs.
  • Detail enrichment on demand. Switch on a fuller description and tab data per bag in search mode; billed only for the records where that extra read actually succeeds.
  • Zero setup. The first run establishes store access automatically and reuses it on every later run; no account or credentials are required to start.

Choose what to collect

These inputs let you configure Too Good To Go Scraper: Stores, Surprise Bags & Availability. Open the actor on Apify to enter your values and review the current options.

Supported input fields
InputWhat it controls
modestringSearch finds surprise bags around one or more locations. URL mode reads one or more item links or numeric item ids. Left unset, a run with item inputs and no search fields reads the items, and a run with locations or search filters searches.

Choices: search, url

locationsarrayWhere to search, one entry per location. A city or place name (Berlin, Paris, 10115 Berlin), or exact coordinates as lat,lng (52.52,13.405). Names are resolved automatically and cached.
radiusKmintegerSearch mode: how far from each point to look, 0.5 to 100 km.
dietCategoriesarraySearch mode: only items matching these diet preferences.
searchPhrasestringSearch mode: only stores whose name or description matches this text.
withStockOnlybooleanSearch mode: hide sold-out listings.
weCareOnlybooleanSearch mode: only stores carrying the We Care label.
Show 19 more inputs
More input fields
InputWhat it controls
favoritesOnlybooleanSearch mode: only stores the account has favorited.
itemInputsarrayURL mode: item page links (any locale, for example toogoodtogo.com/en-us/item/12345678), share links (share.toogoodtogo.com/item/12345678/) or numeric item ids. Store finder pages carry no item id and are skipped with a warning. Multi-value supported.
emailstringStarts the email login: run the actor, open the login email on a desktop browser and confirm it while the run polls (up to 4 minutes). The confirmed session is saved for future runs.
loginPollingIdstringFrom a previous login attempt, paired with the PIN below to complete the login in a second run.
fetchDetailsbooleanFetch each item's detail endpoint for the fuller description and tab data. Adds a per-item request, billed as the detail-enrichment event.
fetchReviewsbooleanFetch each item's reviews (per-user star ratings with their highlighted reasons) and attach them to the record as a nested list, also exposed one-per-row in the Reviews output tab. Works in search and URL mode. Billed as the existing detail-enrichment event, one additional unit per started block of 10 delivered reviews; the per-item detail request this needs is included. Cap and off-switch via Max reviews.
maxReviewsintegerCap on reviews attached per item when Include reviews is on (0 skips review collection entirely).
reviewsOnlybooleanReturn one row per review instead of bag rows (search mode walks the area, URL mode reads the given items). The per-item enrichment reads this needs are performed automatically; each review row carries the item and store references, and is billed only as a normal dataset record: no detail or review surcharges apply.
maxItemsintegerStop after this many records (0 = no limit; the run then stops at Max pages or when results run out).
maxPagesintegerEmpty or 0 uses the built-in ceiling of 100 pages (higher values are capped at 100); the walk stops at Max items or when a location runs out of results.
resumeFromRunIdstringPaste a previous run ID or dataset ID to continue a large pull without returning items already collected there.
incrementalModebooleanTurn this on for daily or recurring monitoring. The first run returns every matching record as NEW. Later runs normally return only NEW, UPDATED and REAPPEARED records. A record becomes UPDATED when any of its delivered fields changes, such as bag availability, quantity, price, pickup window, rating, or store details; changedFields lists which. No field is excluded by default, and you can exclude more with Ignore fields when detecting changes. Reviews are included in the comparison only when Include reviews is on. Turn on Emit unchanged or Emit expired only when you also want those rows returned (and billed). State is kept separately for each search, filter and lookup setup; use State key to name or deliberately share a monitoring campaign.
stateKeystringOptional. Name this monitoring campaign to keep its state stable, or deliberately share state across differently configured runs. Leave empty to let the actor derive a key automatically from the search and filter settings.
emitUnchangedbooleanOff by default. Turn on to also return records that have not changed since the last run, marked UNCHANGED. This returns, and bills, extra rows you already have.
emitExpiredbooleanOff by default. Turn on to also return records that were present in a previous run but are no longer found, marked EXPIRED. Only produced once a run has fully scanned the tracked search.
ignoreFieldsForChangesarrayTop-level record fields that must never make a row UPDATED (for example a field you do not need to monitor). Ignored fields are still delivered and stored; they are just left out of change detection.
mcpConnectorsarrayOptionally send results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize one under Apify, Settings, API & Integrations, then select it here. Notion gets a rich page-per-item export; other connectors get a best-effort write or digest. Leave empty to skip; never changes the dataset output.
notionParentPageUrlstringURL or id of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors.
maxNotifyListingsintegerCap on items written to each connector per run. Does not affect the dataset.

Fields in the output

The documented dataset includes the fields below. Availability can depend on the source page and selected mode.

kindkind
itemIditemId
urlurl
titletitle
itemNameitemName
subtitlesubtitle
descriptiondescription
categorycategory
categoryIconUrlcategoryIconUrl
subCategorysubCategory
itemTypeitemType
storeNamestoreName
Show 74 more fields
branchbranch
priceprice
currencycurrency
valuevalue
valueCurrencyvalueCurrency
savingsPercentsavingsPercent
quantityAvailablequantityAvailable
maxPerOrdermaxPerOrder
pickupStartpickupStart
pickupEndpickupEnd
soldOutAtsoldOutAt
purchaseEndpurchaseEnd
lastItemAtlastItemAt
favoriteCountfavoriteCount
favoritefavorite
ratingAverageratingAverage
ratingCountratingCount
ratingMonthCountratingMonthCount
ratingCollectionExperienceratingCollectionExperience
ratingFoodQualityratingFoodQuality
ratingContentsVarietyratingContentsVariety
ratingFoodQuantityratingFoodQuantity
positiveRatingReasonspositiveRatingReasons
itemTagsitemTags
dietTagsdietTags
packagingOptionpackagingOption
canUserSupplyPackagingcanUserSupplyPackaging
foodHandlingInstructionsfoodHandlingInstructions
collectionInfocollectionInfo
imageUrlimageUrl
logoUrllogoUrl
buffetbuffet
isEdibleisEdible
isSingleisSingle
inventoryTypeinventoryType
newItemnewItem
inSalesWindowinSalesWindow
streetstreet
citycity
postalCodepostalCode
countrycountry
countryCodecountryCode
latitudelatitude
longitudelongitude
distanceKmdistanceKm
pickupStreetpickupStreet
pickupCitypickupCity
pickupPostalCodepickupPostalCode
pickupLatitudepickupLatitude
pickupLongitudepickupLongitude
storeWebsitestoreWebsite
storeTimeZonestoreTimeZone
storeFavoriteCountstoreFavoriteCount
storeDescriptionstoreDescription
storeLogoUrlstoreLogoUrl
storeCoverUrlstoreCoverUrl
storeTaxIdstoreTaxId
storeHiddenstoreHidden
storeIsManufacturerstoreIsManufacturer
storeLocalHerostoreLocalHero
reviewsreviews
reviewCountreviewCount
reviewTotalreviewTotal
enrichedFromDetailenrichedFromDetail
reviewIdreviewId
ratingValueratingValue
reviewTextreviewText
reviewDatereviewDate
authorNameauthorName
reviewReasonsreviewReasons
changeTypechangeType
changedFieldschangedFields
firstSeenAtfirstSeenAt
lastSeenAtlastSeenAt

Example output

An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.

{
  "kind": "bag",
  "itemId": "12345678",
  "url": "https://www.toogoodtogo.com/en-us/item/12345678",
  "title": "Sample Bakery - Mitte (Surprise Bag)",
  "itemName": "Surprise Bag",
  "subtitle": "Baked goods, bread and pastries",
  "description": "A mix of the day's unsold baked goods, contents revealed at pickup.",
  "itemType": "MAGIC_BAG",
  "category": "Baked goods",
  "price": 3.99,
  "currency": "EUR",
  "value": 12,
  "valueCurrency": "EUR",
  "savingsPercent": 66.7,
  "quantityAvailable": 3,
  "maxPerOrder": 2,
  "pickupStart": "2026-01-01T16:30:00Z",
  "pickupEnd": "2026-01-01T18:00:00Z",
  "soldOutAt": null,
  "purchaseEnd": "2026-01-01T18:00:00Z",
  "favoriteCount": 214,
  "favorite": false,
  "ratingAverage": 4.7,
  "ratingCount": 96,
  "ratingMonthCount": 6,
  "ratingCollectionExperience": 4.6,
  "ratingFoodQuality": 4.5,
  "ratingContentsVariety": 3.8,
  "ratingFoodQuantity": 4.1,
  "positiveRatingReasons": [
    "Friendly staff",
    "Great value"
  ],
  "dietTags": [
    "vegetarian"
  ],
  "itemTags": [
    "3 left"
  ],
  "packagingOption": "BRING_YOUR_OWN",
  "canUserSupplyPackaging": true,
  "imageUrl": "https://images.example/cover.jpg",
  "inSalesWindow": true,
  "distanceKm": 1.24,
  "storeId": "10001",
  "storeName": "Sample Bakery",
  "branch": "Mitte",
  "street": "Sample Street 12",
  "city": "Berlin",
  "postalCode": "10115",
  "country": "Germany",
  "countryCode": "DE",
  "latitude": 52.52,
  "longitude": 13.405,
  "storeWebsite": "https://sample-bakery.example",
  "storeTimeZone": "Europe/Berlin",
  "storeFavoriteCount": 1893,
  "storeDescription": "A neighborhood bakery ...",
  "storeRaw": {},
  "raw": {},
  "enrichedFromDetail": true,
  "detail_tabs": [
    {
      "title": "What's inside",
      "body": "Assorted baked goods."
    }
  ],
  "reviews": [
    {
      "reviewId": "r-1001",
      "itemId": "12345678",
      "storeId": "10001",
      "ratingValue": 5,
      "reviewText": "Great bread, friendly staff.",
      "reviewDate": "2026-01-02T10:00:00Z",
      "authorName": "Sample Customer",
      "reviewReasons": [
        "Delicious food"
      ]
    }
  ],
  "reviewCount": 1,
  "reviewTotal": 27
}

Ways to use this data

  • Food-waste shoppers and deal-alert bots: track new surprise bags near one or many neighborhoods as they go live, with price and savings on every listing.
  • Availability monitoring on a schedule: run search mode daily and get only NEW and UPDATED bags since the last check, without re-downloading everything.
  • Sustainability and market research: measure how much discounted surplus food is listed, at what savings, across cities, countries or store categories.
  • Store and brand tracking: paste known store item links to watch price, value and stock changes for specific locations over time.
  • Notion and app integrations: pipe live listings into the apps you already use through the MCP connector export, on top of the dataset export.

Before you run

Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.

Questions about this actor

What data does Too Good To Go Scraper return?

The documented output for Too Good To Go Scraper includes kind, itemid, url, title, itemname, subtitle, description and category. Availability of each field depends on the source page and the selected mode.

How much does Too Good To Go Scraper cost?

It costs $2.50 per 1,000 results on the Apify Free plan and from $1.80 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.

Can I get only new or changed bags on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated records, and unchanged ones are not billed unless you also turn on Emit unchanged.

Why does a pasted item link always add the detail-enrichment charge?

Url mode reads each pasted link or id directly from its own detail page, so it is always fully enriched, the same as a search-mode record with Detail enrichment switched on. The Detail enrichment toggle only controls whether search mode makes that extra per-item request; it has no effect in url mode.

Why did my run fail instead of returning an empty dataset?

If the source can't establish an account session, or every request it made came back rejected, the run stops with a clear message so "no bags right now" is never confused with "nothing could be read". A genuinely empty search (no bags found, nothing rejected) still succeeds with an empty dataset.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

Ready to collect with Too Good To Go Scraper?

Run it on Apify with your own input and export the results as JSON, CSV or Excel.