Install

Find restaurants to book on OpenTable for a date, time and party size.

Searches OpenTable like the site's own search for a cuisine, restaurant name or vibe in a city, for a date, time and party size: name, cuisine, price band, neighbourhood, rating and reviews, how often it was booked recently, address, maximum party size and the restaurant page where the user picks a time. Time slots themselves load separately on OpenTable and are not included yet.

No reports yetRead-only, no login
Site
OpenTable, United States
Version
v1
Runs, last 7 days
No reports yet
sha256
4ad707d7aaf0…

Requests

sent from your browser, in order
  1. 1GET/s?covers&dateTime&termServer-rendered search page; script#primary-window-vars (pure JSON) → windowVariables.__INITIAL_STATE__.multiSearch. The city goes into the free-text term ('sushi new york' resolves the New York City metro).

Parameters

from your agent
citystringCity, e.g. 'New York', 'San Francisco', 'London'. Omit to use OpenTable's guess of the user's area
datestringrequired
party_sizeinteger = 2
querystringrequiredCuisine, restaurant name or keyword, e.g. 'italian', 'sushi', 'rooftop'
timestring = "19:00"

Returns

to your agent
areastringOpenTable metro area actually searched
querystring
restaurantsobject[]address, booked_recently, cuisine, id, max_party_size, name, neighborhood, price_band, rating, reviews, url
totalinteger

Where it can send

  • www.opentable.com

Anything else is blocked by the extension.

Reads from your session

Nothing. Your browser attaches the site's cookies by itself.

Used only in requests to the addresses on the left. Never sent to wield.run or your agent.

Checks

a run passes when
  • length(output.restaurants) > `10`
  • output.area == 'New York City'
  • output.total > `20`
  • starts_with(output.restaurants[0].url, 'https://www.opentable.com/')

Raw recipe

Served as canonical JSON from /api/v1/recipes/opentable.com/search-restaurants, so its sha256 matches the ETag and the index.

Check it yourself
curl -s https://wield.run/api/v1/recipes/opentable.com/search-restaurants | shasum -a 256
# 4ad707d7aaf001dda0966e3c79c1753b2bbe4ad8bb4ad9d9f0e5cb1f2080414b
opentable.com/search-restaurants.json, v1
{
  "description": "Searches OpenTable like the site's own search for a cuisine, restaurant name or vibe in a city, for a date, time and party size: name, cuisine, price band, neighbourhood, rating and reviews, how often it was booked recently, address, maximum party size and the restaurant page where the user picks a time. Time slots themselves load separately on OpenTable and are not included yet.",
  "effect": "read",
  "id": "opentable.com/search-restaurants",
  "keywords": [
    "opentable",
    "restaurant",
    "reservation",
    "book a table",
    "dinner",
    "tisch reservieren",
    "restaurant buchen",
    "date night"
  ],
  "output": {
    "schema": {
      "properties": {
        "area": {
          "description": "OpenTable metro area actually searched",
          "type": [
            "string",
            "null"
          ]
        },
        "query": {
          "type": "string"
        },
        "restaurants": {
          "items": {
            "properties": {
              "address": {
                "type": "string"
              },
              "booked_recently": {
                "description": "Reservations made recently (OpenTable's 'booked N times today' signal)",
                "type": [
                  "integer",
                  "null"
                ]
              },
              "cuisine": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "id": {
                "type": "string"
              },
              "max_party_size": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "name": {
                "type": "string"
              },
              "neighborhood": {
                "type": [
                  "string",
                  "null"
                ]
              },
              "price_band": {
                "description": "e.g. '$31 to $50'",
                "type": [
                  "string",
                  "null"
                ]
              },
              "rating": {
                "type": [
                  "number",
                  "null"
                ]
              },
              "reviews": {
                "type": [
                  "integer",
                  "null"
                ]
              },
              "url": {
                "format": "uri",
                "type": [
                  "string",
                  "null"
                ]
              }
            },
            "type": "object"
          },
          "type": "array"
        },
        "total": {
          "type": [
            "integer",
            "null"
          ]
        }
      },
      "required": [
        "query",
        "restaurants"
      ],
      "type": "object"
    },
    "value": "{query: params.query, area: steps.search.metro, total: steps.search.total, restaurants: steps.search.restaurants}"
  },
  "params": {
    "additionalProperties": false,
    "properties": {
      "city": {
        "description": "City, e.g. 'New York', 'San Francisco', 'London'. Omit to use OpenTable's guess of the user's area",
        "maxLength": 60,
        "type": "string"
      },
      "date": {
        "pattern": "^\\d{4}-\\d{2}-\\d{2}$",
        "type": "string"
      },
      "party_size": {
        "default": 2,
        "maximum": 20,
        "minimum": 1,
        "type": "integer"
      },
      "query": {
        "description": "Cuisine, restaurant name or keyword, e.g. 'italian', 'sushi', 'rooftop'",
        "maxLength": 80,
        "minLength": 2,
        "type": "string"
      },
      "time": {
        "default": "19:00",
        "pattern": "^([01]\\d|2[0-3]):[0-5]\\d$",
        "type": "string"
      }
    },
    "required": [
      "query",
      "date"
    ],
    "type": "object"
  },
  "provenance": {
    "method": "browser-inspect",
    "notes": "spikes/opentable.md. OpenTable drops non-browser connections (curl: no response). In a browser tab the search page embeds script#primary-window-vars (application/json, ~290 KB): multiSearch.restaurants (50 per page), totalRestaurantCount, metro. Verified in-page: 'italian' metroId 4 → 260 results; 'sushi new york' → New York City, 156. No campaign/paid markers seen. Availability slots are fetched later by the page (GraphQL) and are not in the SSR state.",
    "recorded_at": "2026-11-07T12:56:00+01:00",
    "recorded_by": "C4"
  },
  "requires_login": false,
  "schema": "https://wield.run/schema/recipe/v1.json",
  "site": {
    "country": "US",
    "id": "opentable.com",
    "language": "en",
    "login_url": "https://www.opentable.com/authenticate/start",
    "name": "OpenTable",
    "origin": "https://www.opentable.com",
    "origins": [
      "https://www.opentable.com"
    ]
  },
  "steps": [
    {
      "description": "Server-rendered search page; script#primary-window-vars (pure JSON) → windowVariables.__INITIAL_STATE__.multiSearch. The city goes into the free-text term ('sushi new york' resolves the New York City metro).",
      "expect": {
        "content_type": "html",
        "status": [
          200
        ]
      },
      "extract": {
        "embedded_json": {
          "selector": "script#primary-window-vars",
          "vars": {
            "metro": "windowVariables.__INITIAL_STATE__.multiSearch.metro.name",
            "restaurants": "windowVariables.__INITIAL_STATE__.multiSearch.restaurants[].{id: to_string(restaurantId), name: name, cuisine: primaryCuisine.name || `null`, price_band: priceBand.name || `null`, neighborhood: neighborhood.name || `null`, rating: statistics.reviews.ratings.overall.rating || `null`, reviews: statistics.reviews.allTimeTextReviewCount || `null`, booked_recently: statistics.recentReservationCount || `null`, address: join(', ', [address.line1 || '', address.city || '', join(' ', [address.state || '', address.postCode || ''])][?@ != '' && @ != ' ']), max_party_size: features.reservationMaxPartySize || `null`, url: urls.profileLink.link || `null`}",
            "total": "windowVariables.__INITIAL_STATE__.multiSearch.totalRestaurantCount"
          }
        }
      },
      "id": "search",
      "parse": "html",
      "request": {
        "headers": {
          "Accept": "text/html"
        },
        "method": "GET",
        "query": {
          "covers": "{{params.party_size}}",
          "dateTime": "{{params.date}}T{{params.time}}",
          "term": "{{params.query}} {{params.city}}"
        },
        "url": "/s"
      }
    }
  ],
  "task": "Find restaurants to book on OpenTable for a date, time and party size",
  "tos": {
    "notes": "OpenTable's terms prohibit automated access. One user-initiated search at a time from the user's own browser (1 request). Reservations are made by the user on OpenTable.",
    "reviewed": false
  },
  "verify": {
    "checks": [
      "length(output.restaurants) > `10`",
      "output.area == 'New York City'",
      "output.total > `20`",
      "starts_with(output.restaurants[0].url, 'https://www.opentable.com/')"
    ],
    "example_params": {
      "city": "New York",
      "date": "2026-11-20",
      "party_size": 2,
      "query": "sushi",
      "time": "19:00"
    },
    "max_ms": 6000
  },
  "version": 1
}