---
title: "Google Events API: Find Local Events as JSON | Perceptlayer"
description: "Search Google Events as JSON with one GET: q, hl, gl, location and start parameters, a recorded London response, and 1 credit per call."
url: https://perceptlayer.com/blog/google-events-api-local-events
---

[Blog](https://perceptlayer.com/blog) / [API guides](https://perceptlayer.com/blog/category/api-guides)

# Google Events API: Find Local Events as JSON

19 Aug 2026 Perceptlayer 8 min read

Send a `GET` to `/v1/google-events/search` with a query such as `concerts in austin`, and you get Google's event listings back as JSON: title, date, address, venue, ticket links and a thumbnail. The call costs 1 credit, and a failed call costs nothing. This guide covers the parameters, a recorded response, an honest look at the date and location filters, and a small script that builds a city events feed.

## Key takeaways

-   The [Google Events API](https://perceptlayer.com/apis/google-events) has one endpoint, `GET /v1/google-events/search`. Only `q` is required; `hl`, `gl`, `location`, `uule`, `htichips` and `start` are optional.
-   Each successful call costs 1 credit. A 50-city feed that runs three queries per city costs 150 credits per refresh.
-   There is no date parameter you can rely on. Put the timeframe in `q` ("this weekend"), then filter on `date.start_time`, which is in UTC.
-   Location comes from the wording of `q`, `location`, `uule` and `gl`. Treat them as hints and check `address` in the results.
-   Free accounts get 1,000 credits a month, so you can build and test a feed before buying anything.

## What does the Google Events API return?

The endpoint returns the event cards Google shows for a search such as "events in london this weekend", as structured JSON. Each item in `events_results` has a `position`, `title`, a `date` object, an `address` array, a `link`, a `venue` object, `ticket_info` entries and a `thumbnail`. The response also echoes your inputs in `search_parameters` and includes a `pagination` object.

That makes it a fit for city guides, "what's on" widgets, newsletters and agents that answer "what can I do this weekend". It isn't a catalogue of every event in a city. You get what Google ranks for the query you send, and the data is collected from publicly available sources and returned as found at the time of the call.

If you need ticketing, inventory or on-sale data from a single organiser, that organiser's own API usually fits better. Ticketmaster, for example, publishes its own [Discovery API](https://developer.ticketmaster.com/products-and-docs/apis/discovery-api/v2/) for its events. For breadth across venues and organisers in one query, a search-based endpoint is the more practical route.

## How do you make your first request?

Send the key in the `X-API-Key` header and put the search in `q`. Keys start with `sk_live_`, and you get one free by [signing up](https://perceptlayer.com/signup) and verifying an email address. The [authentication docs](https://docs.perceptlayer.com/authentication) cover the `api_key` query parameter for places where headers aren't possible.

```bash
curl "https://api.perceptlayer.com/v1/google-events/search?q=concerts+in+austin&hl=en&gl=us" \
  -H "X-API-Key: $API_KEY"
```

Every successful response carries `X-Credits-Used` and `X-Credits-Remaining` headers, so you can check what the call cost without parsing the body. You can also run the same call from the playground on the [Google Events search endpoint page](https://perceptlayer.com/apis/google-events/search) before writing any code.

## Which parameters does the search endpoint take?

The endpoint takes one required parameter, `q`, and six optional ones. Types and length limits are the only documented constraints, so the table sticks to those and adds notes on how each one is meant to be used.

| Parameter | Type | Required | Limit | Notes |
| --- | --- | --- | --- | --- |
| `q` | string | yes | 255 characters | The search text, such as `events in london this weekend`. |
| `hl` | string | no | none documented | Interface language, for example `en`. |
| `gl` | string | no | 2 characters | Country code, for example `us`. |
| `location` | string | no | 255 characters | A place name to anchor the search. |
| `uule` | string | no | 500 characters | Google's encoded location value, for when you already have one. |
| `htichips` | string | no | 200 characters | A filter chip value. Allowed values aren't documented here. |
| `start` | integer | no | none documented | Result offset, for paging. |

Defaults and page sizes aren't documented, so don't hard-code either. Read `events_results` and `pagination` in the response instead.

Invalid input returns `invalid_parameters` (422), for example a `q` over 255 characters. The [errors docs](https://docs.perceptlayer.com/errors) list every code, and since a failed call costs nothing, a bad request is only a lost minute.

## What does a real response look like?

Here is a recorded response for `q=events in london this weekend` with `hl=en` and `gl=uk`. The excerpt is trimmed with `…` and shows the first event only.

```bash
curl "https://api.perceptlayer.com/v1/google-events/search?q=events+in+london+this+weekend&hl=en&gl=uk" \
  -H "X-API-Key: $API_KEY"
```

```json
{
  "search_parameters": {
    "engine": "google_events",
    "q": "events in london this weekend",
    "gl": "uk",
    "hl": "en",
    "start": 0
  },
  "search_information": {
    "events_results_state": "Results for exact spelling"
  },
  "events_results": [
    {
      "position": 1,
      "title": "Halloween River Cruise",
      "date": {
        "when": "Sat, 24 Oct 2026, 19:00",
        "start_time": "2026-10-24T18:00:00Z",
        "end_time": "2026-10-24T19:00:00Z"
      },
      "address": [
        "Riverside Building, London Eye, County Hall, Westminster Bridge Rd, London SE1 7PB"
      ],
      "description": "A 60-minute London Eye River Cruise along the Thames with live actors telling ghost stories of Jack the Ripper, the ghost of Captain Kidd and the haunted cries …",
      "ticket_info": [
        {
          "source": "Mato Events",
          "link": "https://ma.to/event/london-eye-halloween-river-cruise-2026-10-24",
          "link_type": "tickets"
        },
        {
          "source": "londoneye.com",
          "link": "https://www.londoneye.com/",
          "link_type": "more info"
        }
      ],
      "venue": {
        "name": "London Eye",
        "rating": 4.5,
        "reviews": 206031,
        "link": "https://www.google.com/search?q=London+Eye&ludocid=4796882358840715922"
      },
      "thumbnail": "https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcSIyGJkdedlIlKt-RDN0ud-FP177CCvK_cM-VDPtGilIsEngLzXTMXfTGmHpgIvc6S0f3hXZaJaUcgcI3w"
    }
  ],
  "pagination": {
    "current_page": 1,
    "start": 0
  }
}
```

A few details in the recording matter when you build on it:

-   `date.when` is display text in local time ("Sat, 24 Oct 2026, 19:00"), while `start_time` is UTC. The 19:00 event has a `start_time` of `18:00:00Z` because London was on summer time that day.
-   The second event in the recording, a ghost walk, has `when` set to "Sun, 25 Oct 2026" with no clock time. Its `start_time` and `end_time` are both `2026-10-24T23:00:00Z`. Date-only events can have identical start and end times, so don't treat the pair as a duration.
-   `description` is cut off with an ellipsis and the same event shows `?` where the source text had other characters. Show it as a teaser, and link to the event instead of republishing it.
-   `ticket_info` mixes `tickets` and `more info` links, distinguished by `link_type`.

## How reliable are the date and location filters?

There is no `date` or `from`/ `to` parameter. The timeframe lives in the wording of `q` ("tonight", "this weekend", "in november") and possibly in `htichips`, whose accepted values aren't documented here. Both steer Google's ranking. Neither guarantees every result falls inside your window, so filter again on your side.

The recorded call above is a fair example: it asked for "this weekend" and the events it holds fall on 24 and 25 October 2026. That is what you'd hope for, but it comes from Google's interpretation of the phrase, and "weekend" depends on the day you run the query.

Location works the same way:

-   **In `q`**: "concerts in austin" carries the city in the text, as in the first example.
-   **`location`**: a free-text place name up to 255 characters, for when you'd rather keep the city out of the query.
-   **`uule`**: Google's encoded location string, useful if you already generate them.
-   **`gl`**: a two-character country bias. The recorded call used `gl=uk`, and it returned London events. Google's own code for the United Kingdom is usually `gb`, and we haven't documented the accepted `gl` values, so try `gb` if `uk` doesn't bias results the way you expect.

Compare `address` against the city you asked for and drop mismatches. Run a few queries in the playground before choosing between `location` and a city in `q`, because we haven't documented which wins when they disagree.

## How do you build a city events feed?

A city feed is a handful of query phrasings per city, a page or two of each, merged and deduplicated, then filtered to a time window. The script below does that with `requests`. It pages by advancing `start` by the number of events it just received, which assumes `start` is a plain offset. Confirm that in the playground before relying on it.

```python
import os
import time
from datetime import datetime, timedelta, timezone
from zoneinfo import ZoneInfo

import requests

URL = "https://api.perceptlayer.com/v1/google-events/search"
HEADERS = {"X-API-Key": os.environ["API_KEY"]}

def fetch(q, gl, start=0):
    for _ in range(3):
        r = requests.get(
            URL,
            params={"q": q, "hl": "en", "gl": gl, "start": start},
            headers=HEADERS,
            timeout=30,
        )
        if r.status_code in (429, 503):
            time.sleep(int(r.headers.get("Retry-After", "5")))
            continue
        r.raise_for_status()
        return r.json()
    raise RuntimeError(f"gave up on {q!r}")

def city_feed(city, gl, tz, days=7, pages=2):
    phrasings = [f"events in {city} this weekend", f"concerts in {city}", f"things to do in {city}"]
    now = datetime.now(timezone.utc)
    cutoff = now + timedelta(days=days)
    seen = {}
    for q in phrasings:
        start = 0
        for _ in range(pages):
            events = fetch(q, gl, start).get("events_results", [])
            if not events:
                break
            for e in events:
                when = e.get("date", {}).get("start_time")
                if not when:
                    continue
                begins = datetime.fromisoformat(when.replace("Z", "+00:00"))
                if not now <= begins <= cutoff:
                    continue
                key = (e["title"].lower(), when, e.get("venue", {}).get("name"))
                seen.setdefault(key, {
                    "title": e["title"],
                    "starts_local": begins.astimezone(ZoneInfo(tz)).isoformat(),
                    "venue": e.get("venue", {}).get("name"),
                    "address": ", ".join(e.get("address", [])),
                    "tickets": [t["link"] for t in e.get("ticket_info", []) if t.get("link_type") == "tickets"],
                })
            start += len(events)
    return sorted(seen.values(), key=lambda e: e["starts_local"])

if __name__ == "__main__":
    for event in city_feed("london", "uk", "Europe/London"):
        print(event["starts_local"], event["title"], "-", event["venue"])
```

Three details in that script come straight from the recorded response. It filters on `start_time` because that field is machine-readable UTC. It converts to the city's time zone for display. And it deduplicates on title, start time and venue, because the same event can surface under more than one query. The same idea at larger scale is in [deduplicating listings across sources](https://perceptlayer.com/blog/deduplicate-listings-across-sources).

The script retries `429` and `503` after the `Retry-After` seconds. One caution: requests have no idempotency key, so a call that timed out on your side may still have succeeded and been billed. The [rate limits docs](https://docs.perceptlayer.com/rate-limits) cover the per-minute counts, and free accounts get 1 request a second.

## What does an events feed cost per refresh?

Every successful call costs 1 credit, so a refresh costs queries × pages × cities, in credits. Failed calls cost nothing and return `X-Credits-Used: 0`. The script above runs 3 phrasings with up to 2 pages each, so one city costs at most 6 credits per refresh.

| Setup | Calls | Credits |
| --- | --- | --- |
| 1 city, 3 phrasings, 2 pages | 6 | 6 |
| 50 cities, 3 phrasings, 1 page | 150 | 150 |
| 50 cities, 3 phrasings, 2 pages, daily for 30 days | 9,000 | 9,000 |

The last row is 50 × 3 × 2 = 300 calls a day, and 300 calls × 30 days × 1 credit = 9,000 credits. That fits inside the Starter pack's 10,000 credits, and purchased credits last 12 months. The monthly free tier of 1,000 credits covers about three days of that feed, or a full test of a few cities. See [pricing](https://perceptlayer.com/pricing) for what credits cost and [how credits are counted](https://docs.perceptlayer.com/credits) for the details.

Cutting cost is mostly a question of calls you don't make. Most event lists don't change by the hour, so a daily or twice-daily refresh is enough for a guide or a newsletter. If you need to schedule the pulls, [cron, queues or workflows](https://perceptlayer.com/blog/schedule-web-data-pulls-cron-queue) compares the options.

## When should you use this instead of another source?

Use the endpoint when you want what people see in a Google events search, across many venues, without scraping it yourself. Use your own pipeline, or an organiser's API, when you need complete inventory for one venue or one ticketing platform. The endpoint returns ranked search results, not a database of everything on sale.

If you publish events on your own site, Google documents how to mark them up in its [event structured data guide](https://developers.google.com/search/docs/appearance/structured-data/event). That is the reverse direction: it helps your events appear in Google, while this endpoint reads what Google shows. Both are useful if you run a venue and also want to track what's listed around you.

For agents, the same endpoint is available through the MCP server, so an assistant can answer "what's on in Lisbon on Saturday" with a live call. The [AI agents docs](https://docs.perceptlayer.com/ai-agents) show how to add it. For related Google endpoints, [Google Hotels](https://perceptlayer.com/blog/google-hotels-api) pairs naturally with an events feed for trip planning, and the [Google Places alternative](https://perceptlayer.com/blog/google-maps-places-api-alternative) covers venue data.

Your next step: [get a free API key](https://perceptlayer.com/signup), then run `concerts in austin` from the playground on the [Google Events search page](https://perceptlayer.com/apis/google-events/search) and compare the `address` fields with the city you asked for.

## APIs in this post

-   [Google Events **1 credit per call** · 1 endpoint](https://perceptlayer.com/apis/google-events)

## Frequently asked questions

### How much does a Google Events API call cost?

A successful call to `/v1/google-events/search` costs 1 credit. Failed calls cost nothing and return `X-Credits-Used: 0`. Free accounts get 1,000 credits a month after verifying an email address, with no credit card. That's 1,000 calls a month before you buy anything. The [pricing page](https://perceptlayer.com/pricing) shows what credit packs cost.

### Can I filter Google events by date?

There's no date parameter. Put the timeframe in `q`, such as "this weekend" or "tonight", and then filter the results on `date.start_time`, which is in UTC. `htichips` also accepts a filter string, but its allowed values aren't documented, so test any value in the playground first.

### How do I get events for a specific city?

Include the city in `q`, as in `concerts in austin`, or pass a place name in `location`. You can also add `gl` for the country. Then check each result's `address` array against your city, because these inputs steer the ranking and don't guarantee that every result matches.

### What happens when I hit the rate limit?

You get a `429` response with a `Retry-After` header giving the seconds to wait. Free accounts get 1 request a second, and paid accounts run at the rate of the credits they're using, at least 5 a second. Wait the stated time and retry. The [rate limits docs](https://docs.perceptlayer.com/rate-limits) have the details.

### Is there a way to call it from an AI agent?

Yes. The MCP server at `https://api.perceptlayer.com/mcp` exposes `search_endpoints`, `get_endpoint` and `call_endpoint`. The first two only look up the catalogue and cost nothing. `call_endpoint` runs the Google Events search and spends 1 credit on success. See the [AI agents docs](https://docs.perceptlayer.com/ai-agents).

google events local events events api search json

## More from the blog

1.  [API guides](https://perceptlayer.com/blog/category/api-guides) 14 Oct 2026 Perceptlayer 7 min read
    
    ## [Google News API: Search News Articles as JSON](https://perceptlayer.com/blog/google-news-api)
    
    One GET call to /v1/google-news/news returns articles with title, link, source and ISO date as JSON for 1 credit. Parameters, a real response, cost.
    
2.  [API guides](https://perceptlayer.com/blog/category/api-guides) 13 Oct 2026 Perceptlayer 6 min read
    
    ## [Google Patents API: Search Patents and Get Details](https://perceptlayer.com/blog/google-patents-api-search-details)
    
    Search Google Patents by keyword, inventor or assignee with one GET call, then fetch full details by patent\_id. Both endpoints cost 1 credit per call.
    
3.  [API guides](https://perceptlayer.com/blog/category/api-guides) 7 Aug 2026 Updated 26 Oct 2026 Perceptlayer 6 min read
    
    ## [Yelp Reviews API: Business Search and Reviews as JSON](https://perceptlayer.com/blog/yelp-reviews-api-json)
    
    Three Yelp endpoints return search results, business details and reviews as JSON, 1 credit per call. Parameters, a real response and a cost example.
