googlemaps-kit 0.6.0 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +54 -2
- package/dist/books.d.ts +30 -0
- package/dist/books.d.ts.map +1 -0
- package/dist/books.js +77 -0
- package/dist/books.js.map +1 -0
- package/dist/client/http-client.d.ts +3 -1
- package/dist/client/http-client.d.ts.map +1 -1
- package/dist/client/http-client.js +14 -3
- package/dist/client/http-client.js.map +1 -1
- package/dist/client/namespaces.d.ts +1 -4
- package/dist/client/namespaces.d.ts.map +1 -1
- package/dist/client/namespaces.js +1 -5
- package/dist/client/namespaces.js.map +1 -1
- package/dist/finance/client.d.ts +19 -0
- package/dist/finance/client.d.ts.map +1 -0
- package/dist/finance/client.js +75 -0
- package/dist/finance/client.js.map +1 -0
- package/dist/finance/parsers.d.ts +13 -0
- package/dist/finance/parsers.d.ts.map +1 -0
- package/dist/finance/parsers.js +146 -0
- package/dist/finance/parsers.js.map +1 -0
- package/dist/finance/types.d.ts +76 -0
- package/dist/finance/types.d.ts.map +1 -0
- package/dist/finance/types.js +2 -0
- package/dist/finance/types.js.map +1 -0
- package/dist/finance.d.ts +5 -0
- package/dist/finance.d.ts.map +1 -0
- package/dist/finance.js +4 -0
- package/dist/finance.js.map +1 -0
- package/dist/flights/client.d.ts +9 -0
- package/dist/flights/client.d.ts.map +1 -0
- package/dist/flights/client.js +14 -0
- package/dist/flights/client.js.map +1 -0
- package/dist/flights/parsers.d.ts +11 -0
- package/dist/flights/parsers.d.ts.map +1 -0
- package/dist/flights/parsers.js +64 -0
- package/dist/flights/parsers.js.map +1 -0
- package/dist/flights/types.d.ts +52 -0
- package/dist/flights/types.d.ts.map +1 -0
- package/dist/flights/types.js +2 -0
- package/dist/flights/types.js.map +1 -0
- package/dist/flights.d.ts +5 -0
- package/dist/flights.d.ts.map +1 -0
- package/dist/flights.js +4 -0
- package/dist/flights.js.map +1 -0
- package/dist/gemini-web/client.d.ts +16 -0
- package/dist/gemini-web/client.d.ts.map +1 -0
- package/dist/gemini-web/client.js +110 -0
- package/dist/gemini-web/client.js.map +1 -0
- package/dist/gemini-web/parsers.d.ts +5 -0
- package/dist/gemini-web/parsers.d.ts.map +1 -0
- package/dist/gemini-web/parsers.js +62 -0
- package/dist/gemini-web/parsers.js.map +1 -0
- package/dist/gemini-web/types.d.ts +47 -0
- package/dist/gemini-web/types.d.ts.map +1 -0
- package/dist/gemini-web/types.js +2 -0
- package/dist/gemini-web/types.js.map +1 -0
- package/dist/gemini-web.d.ts +5 -0
- package/dist/gemini-web.d.ts.map +1 -0
- package/dist/gemini-web.js +4 -0
- package/dist/gemini-web.js.map +1 -0
- package/dist/google-search/client.d.ts +16 -0
- package/dist/google-search/client.d.ts.map +1 -0
- package/dist/google-search/client.js +117 -0
- package/dist/google-search/client.js.map +1 -0
- package/dist/google-search/errors.d.ts +8 -0
- package/dist/google-search/errors.d.ts.map +1 -0
- package/dist/google-search/errors.js +13 -0
- package/dist/google-search/errors.js.map +1 -0
- package/dist/google-search/html.d.ts +12 -0
- package/dist/google-search/html.d.ts.map +1 -0
- package/dist/google-search/html.js +135 -0
- package/dist/google-search/html.js.map +1 -0
- package/dist/google-search/parsers.d.ts +6 -0
- package/dist/google-search/parsers.d.ts.map +1 -0
- package/dist/google-search/parsers.js +177 -0
- package/dist/google-search/parsers.js.map +1 -0
- package/dist/google-search/types.d.ts +66 -0
- package/dist/google-search/types.d.ts.map +1 -0
- package/dist/google-search/types.js +2 -0
- package/dist/google-search/types.js.map +1 -0
- package/dist/google-search.d.ts +6 -0
- package/dist/google-search.d.ts.map +1 -0
- package/dist/google-search.js +4 -0
- package/dist/google-search.js.map +1 -0
- package/dist/hotels/client.d.ts +9 -0
- package/dist/hotels/client.d.ts.map +1 -0
- package/dist/hotels/client.js +14 -0
- package/dist/hotels/client.js.map +1 -0
- package/dist/hotels/parsers.d.ts +7 -0
- package/dist/hotels/parsers.d.ts.map +1 -0
- package/dist/hotels/parsers.js +74 -0
- package/dist/hotels/parsers.js.map +1 -0
- package/dist/hotels/types.d.ts +55 -0
- package/dist/hotels/types.d.ts.map +1 -0
- package/dist/hotels/types.js +2 -0
- package/dist/hotels/types.js.map +1 -0
- package/dist/hotels.d.ts +4 -0
- package/dist/hotels.d.ts.map +1 -0
- package/dist/hotels.js +3 -0
- package/dist/hotels.js.map +1 -0
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/known-surfaces.d.ts +0 -6
- package/dist/known-surfaces.d.ts.map +1 -1
- package/dist/known-surfaces.js +0 -6
- package/dist/known-surfaces.js.map +1 -1
- package/dist/lens/client.d.ts +14 -0
- package/dist/lens/client.d.ts.map +1 -0
- package/dist/lens/client.js +116 -0
- package/dist/lens/client.js.map +1 -0
- package/dist/lens/errors.d.ts +8 -0
- package/dist/lens/errors.d.ts.map +1 -0
- package/dist/lens/errors.js +13 -0
- package/dist/lens/errors.js.map +1 -0
- package/dist/lens/types.d.ts +27 -0
- package/dist/lens/types.d.ts.map +1 -0
- package/dist/lens/types.js +2 -0
- package/dist/lens/types.js.map +1 -0
- package/dist/lens.d.ts +8 -0
- package/dist/lens.d.ts.map +1 -0
- package/dist/lens.js +5 -0
- package/dist/lens.js.map +1 -0
- package/dist/news.d.ts +46 -0
- package/dist/news.d.ts.map +1 -0
- package/dist/news.js +202 -0
- package/dist/news.js.map +1 -0
- package/dist/pagespeed/client.d.ts +28 -0
- package/dist/pagespeed/client.d.ts.map +1 -0
- package/dist/pagespeed/client.js +222 -0
- package/dist/pagespeed/client.js.map +1 -0
- package/dist/pagespeed/errors.d.ts +9 -0
- package/dist/pagespeed/errors.d.ts.map +1 -0
- package/dist/pagespeed/errors.js +15 -0
- package/dist/pagespeed/errors.js.map +1 -0
- package/dist/pagespeed/parsers.d.ts +7 -0
- package/dist/pagespeed/parsers.d.ts.map +1 -0
- package/dist/pagespeed/parsers.js +236 -0
- package/dist/pagespeed/parsers.js.map +1 -0
- package/dist/pagespeed/types.d.ts +156 -0
- package/dist/pagespeed/types.d.ts.map +1 -0
- package/dist/pagespeed/types.js +2 -0
- package/dist/pagespeed/types.js.map +1 -0
- package/dist/pagespeed/wire.d.ts +10 -0
- package/dist/pagespeed/wire.d.ts.map +1 -0
- package/dist/pagespeed/wire.js +96 -0
- package/dist/pagespeed/wire.js.map +1 -0
- package/dist/pagespeed.d.ts +6 -0
- package/dist/pagespeed.d.ts.map +1 -0
- package/dist/pagespeed.js +4 -0
- package/dist/pagespeed.js.map +1 -0
- package/dist/platform/catalog.d.ts.map +1 -1
- package/dist/platform/catalog.js +0 -9
- package/dist/platform/catalog.js.map +1 -1
- package/dist/services/environment/air-quality.d.ts.map +1 -1
- package/dist/services/environment/air-quality.js +3 -7
- package/dist/services/environment/air-quality.js.map +1 -1
- package/dist/services/environment/weather.d.ts +4 -1
- package/dist/services/environment/weather.d.ts.map +1 -1
- package/dist/services/environment/weather.js +12 -3
- package/dist/services/environment/weather.js.map +1 -1
- package/dist/services/reviews.d.ts.map +1 -1
- package/dist/services/reviews.js +4 -1
- package/dist/services/reviews.js.map +1 -1
- package/dist/translate.d.ts +75 -0
- package/dist/translate.d.ts.map +1 -0
- package/dist/translate.js +126 -0
- package/dist/translate.js.map +1 -0
- package/dist/travel-google/common.d.ts +24 -0
- package/dist/travel-google/common.d.ts.map +1 -0
- package/dist/travel-google/common.js +72 -0
- package/dist/travel-google/common.js.map +1 -0
- package/dist/trends/client.d.ts +17 -0
- package/dist/trends/client.d.ts.map +1 -0
- package/dist/trends/client.js +86 -0
- package/dist/trends/client.js.map +1 -0
- package/dist/trends/errors.d.ts +8 -0
- package/dist/trends/errors.d.ts.map +1 -0
- package/dist/trends/errors.js +13 -0
- package/dist/trends/errors.js.map +1 -0
- package/dist/trends/links.d.ts +8 -0
- package/dist/trends/links.d.ts.map +1 -0
- package/dist/trends/links.js +71 -0
- package/dist/trends/links.js.map +1 -0
- package/dist/trends/parsers.d.ts +5 -0
- package/dist/trends/parsers.d.ts.map +1 -0
- package/dist/trends/parsers.js +126 -0
- package/dist/trends/parsers.js.map +1 -0
- package/dist/trends/types.d.ts +71 -0
- package/dist/trends/types.d.ts.map +1 -0
- package/dist/trends/types.js +2 -0
- package/dist/trends/types.js.map +1 -0
- package/dist/trends.d.ts +9 -0
- package/dist/trends.d.ts.map +1 -0
- package/dist/trends.js +8 -0
- package/dist/trends.js.map +1 -0
- package/dist/types/common.d.ts +0 -2
- package/dist/types/common.d.ts.map +1 -1
- package/dist/types/common.js.map +1 -1
- package/dist/utils/google-web.d.ts +24 -0
- package/dist/utils/google-web.d.ts.map +1 -0
- package/dist/utils/google-web.js +150 -0
- package/dist/utils/google-web.js.map +1 -0
- package/dist/youtube/client.d.ts +19 -0
- package/dist/youtube/client.d.ts.map +1 -0
- package/dist/youtube/client.js +115 -0
- package/dist/youtube/client.js.map +1 -0
- package/dist/youtube/errors.d.ts +8 -0
- package/dist/youtube/errors.d.ts.map +1 -0
- package/dist/youtube/errors.js +13 -0
- package/dist/youtube/errors.js.map +1 -0
- package/dist/youtube/parsers.d.ts +9 -0
- package/dist/youtube/parsers.d.ts.map +1 -0
- package/dist/youtube/parsers.js +213 -0
- package/dist/youtube/parsers.js.map +1 -0
- package/dist/youtube/types.d.ts +90 -0
- package/dist/youtube/types.d.ts.map +1 -0
- package/dist/youtube/types.js +2 -0
- package/dist/youtube/types.js.map +1 -0
- package/dist/youtube.d.ts +9 -0
- package/dist/youtube.d.ts.map +1 -0
- package/dist/youtube.js +6 -0
- package/dist/youtube.js.map +1 -0
- package/docs/books.md +18 -0
- package/docs/environment-research.md +65 -0
- package/docs/finance-research.md +153 -0
- package/docs/finance.md +43 -0
- package/docs/gemini-web.md +36 -0
- package/docs/google-ai-books-research.md +53 -0
- package/docs/google-media-research.md +105 -0
- package/docs/google-search-research.md +36 -0
- package/docs/google-search.md +53 -0
- package/docs/google-services-research.md +135 -0
- package/docs/google-travel-research.md +86 -0
- package/docs/internal/reverse-engineering.md +85 -0
- package/docs/lens.md +54 -0
- package/docs/maps-revalidation.md +31 -0
- package/docs/news.md +35 -0
- package/docs/pagespeed-research.md +153 -0
- package/docs/pagespeed.md +135 -0
- package/docs/reviews-research.md +33 -0
- package/docs/translate.md +78 -0
- package/docs/trends-research.md +82 -0
- package/docs/trends.md +75 -0
- package/docs/youtube.md +72 -0
- package/package.json +77 -2
- package/dist/services/aerial-view.d.ts +0 -22
- package/dist/services/aerial-view.d.ts.map +0 -1
- package/dist/services/aerial-view.js +0 -107
- package/dist/services/aerial-view.js.map +0 -1
- package/dist/types/aerial-view.d.ts +0 -39
- package/dist/types/aerial-view.d.ts.map +0 -1
- package/dist/types/aerial-view.js +0 -2
- package/dist/types/aerial-view.js.map +0 -1
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
# Google Finance consumer client
|
|
2
|
+
|
|
3
|
+
Investigated and verified on **2026-10-29**, build
|
|
4
|
+
`boq_finhub-uiserver_20261026.07_p0`. This client implements the public consumer
|
|
5
|
+
quote, instrument-suggestion, and sampled-price chart surfaces. It does not
|
|
6
|
+
claim to reproduce all of Google Finance, provide a licensed market-data feed,
|
|
7
|
+
or expose paid/AI research features.
|
|
8
|
+
|
|
9
|
+
```ts
|
|
10
|
+
import { finance } from 'googlemaps-kit/finance';
|
|
11
|
+
|
|
12
|
+
const client = finance();
|
|
13
|
+
const quote = await client.quote('GOOGL:NASDAQ');
|
|
14
|
+
const suggestions = await client.search('Microsoft');
|
|
15
|
+
const chart = await client.chart('GOOGL:NASDAQ', { range: '1M' });
|
|
16
|
+
|
|
17
|
+
console.log(quote.price, quote.currency, quote.time);
|
|
18
|
+
console.log(quote.extendedMarket);
|
|
19
|
+
console.log(suggestions.matches);
|
|
20
|
+
console.log(chart.sessions.flatMap(session => session.points));
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Instrument strings use **symbol:exchange** order, as Google Finance URLs do.
|
|
24
|
+
Objects `{ symbol: 'GOOGL', exchange: 'NASDAQ' }` are also accepted. `search`
|
|
25
|
+
returns identifiable instrument suggestions, deduplicating repeated UI groups;
|
|
26
|
+
it does not return an arbitrary natural-language or AI answer.
|
|
27
|
+
|
|
28
|
+
Configuration supports `fetch`, `timeoutMs`, `language`, and `userAgent`.
|
|
29
|
+
Methods accept an `AbortSignal`. Requests have a body-read deadline and do not
|
|
30
|
+
automatically retry a block or failure. `FinanceError` exports the shared
|
|
31
|
+
`GoogleWebError` class with `kind`, optional HTTP `status`, `rpcCode`, and
|
|
32
|
+
`retryAfterMs`. Rate-limit/automated-query responses remain errors.
|
|
33
|
+
|
|
34
|
+
## Runtime and static evidence
|
|
35
|
+
|
|
36
|
+
- Ordinary headless Chromium rendered a complete GOOGL quote page. A generic
|
|
37
|
+
non-browser user agent had previously received an unsupported-client page.
|
|
38
|
+
The client therefore uses the exact captured browser user-agent family for
|
|
39
|
+
device negotiation; users may override it. Runtime browser evidence:
|
|
40
|
+
`ev_8b8ce4e3adf9f17541b4db84cde49b10828e312435ad8735c6596efac93c2ccd`.
|
|
41
|
+
- REA analyzed **66 observed scripts**, providing static descriptors and field
|
|
42
|
+
access evidence:
|
|
43
|
+
`ev_681d6f6b8601b800f9884383e2c34fd76024911ff6b8305bd91f61b0f7c97950`.
|
|
44
|
+
Static analysis does not establish endpoint execution; direct HTTP replay
|
|
45
|
+
below supplies the runtime verification.
|
|
46
|
+
- Direct anonymous HTTP replay returned 200 with real data for quote summary,
|
|
47
|
+
search suggestions, pricing details, and all eight chart ranges. No API key
|
|
48
|
+
or signed-in cookies were supplied. The complete client also passed an
|
|
49
|
+
opted-in live test for quote, search, and monthly chart.
|
|
50
|
+
- Original runtime HTML, requests, responses, and scripts remain in untracked
|
|
51
|
+
scratch storage. Offline tests use copied public-data payloads under
|
|
52
|
+
`tests/fixtures/finance/`; shipped code has no dependency on scratch files.
|
|
53
|
+
|
|
54
|
+
## Verified protocol
|
|
55
|
+
|
|
56
|
+
Bootstrap `https://www.google.com/finance/?hl=en` and read `WIZ_global_data`:
|
|
57
|
+
`eptZe=/finance/_/FinHubUi/`, `FdrFJe` session, and `cfb2h` build. Calls POST
|
|
58
|
+
form-encoded `f.req` to
|
|
59
|
+
`https://www.google.com/finance/_/FinHubUi/data/batchexecute`, passing `rpcids`,
|
|
60
|
+
`source-path`, `f.sid`, `bl`, `hl`, and `rt=c`. Responses contain XSSI-prefixed,
|
|
61
|
+
framed `wrb.fr` JSON payloads. Captured anonymous requests omitted `at`.
|
|
62
|
+
|
|
63
|
+
| RPC | Shipped descriptor | Verified arguments | Client method |
|
|
64
|
+
| --- | --- | --- | --- |
|
|
65
|
+
| `gCvqoe` | `/FinanceHubService.ListEntitySummary` | `[[[null,[symbol,exchange]]]]` | `quote` |
|
|
66
|
+
| `XB3kn` | `/FinanceHubService.GetSearchSuggestions` | `[query,null,1]` | `search` |
|
|
67
|
+
| `c2u4wc` | `/FinanceHubService.ListHistoricalPricingData` | `[[[null,[symbol,exchange]]],rangeEnum]` | `chart` |
|
|
68
|
+
| `dlNq8b` | Pricing-detail surface | `[[[null,[symbol,exchange]]],1,1,1]` | Captured and replayed; not exposed by this client |
|
|
69
|
+
|
|
70
|
+
Browser traffic also registered and sometimes executed earnings/research RPCs,
|
|
71
|
+
including `Xs5i3b` (GetEarningsTranscriptHighlights), `Iaiw6c` (GetEarningsFiles),
|
|
72
|
+
and `TNo8E` (GetRelatedEarnings). Those are not the quote/search endpoints and
|
|
73
|
+
are not part of the public SDK contract. No claim of paid research parity is
|
|
74
|
+
made from their presence in a bundle.
|
|
75
|
+
|
|
76
|
+
### Quote fields
|
|
77
|
+
|
|
78
|
+
`gCvqoe` response field 1 is repeated EntitySummary; each entry's field 1 is a
|
|
79
|
+
security node. The following are one-based security field numbers:
|
|
80
|
+
|
|
81
|
+
| Field | Meaning established by capture and renderer |
|
|
82
|
+
| --- | --- |
|
|
83
|
+
| 1 | Entity ID |
|
|
84
|
+
| 2 | `[symbol,exchange]` |
|
|
85
|
+
| 3 | Display name |
|
|
86
|
+
| 5 | Currency |
|
|
87
|
+
| 6 | Regular price tuple `[price,change,changePercent,...]` |
|
|
88
|
+
| 8 | Previous close |
|
|
89
|
+
| 12 | Reported data timestamp `[seconds,nanos]` |
|
|
90
|
+
| 13 | Exchange time-zone name |
|
|
91
|
+
| 14 | UTC offset seconds |
|
|
92
|
+
| 17 | Extended-session price tuple |
|
|
93
|
+
| 18 | Regular price timestamp |
|
|
94
|
+
| 19 | Extended-session price timestamp |
|
|
95
|
+
| 25 | Source enum; returned as an opaque code when present |
|
|
96
|
+
|
|
97
|
+
The successful GOOGL capture contained regular price **324.89 USD** and
|
|
98
|
+
extended price **292.50 USD**. These are fixture observations, not current
|
|
99
|
+
recommendations or promised live prices. The parser keeps them separate and
|
|
100
|
+
preserves zero prices/changes and original precision.
|
|
101
|
+
|
|
102
|
+
`reportedTime`, `time`, and `extendedMarket.time` are distinct source values.
|
|
103
|
+
The payload does not establish a guaranteed delay interval, so `delayStatus`
|
|
104
|
+
is `not-disclosed`; the SDK does not label every quote real-time. Some exchanges
|
|
105
|
+
or instruments can be delayed, missing, or unsupported. See Google's
|
|
106
|
+
[Finance data disclaimer](https://www.google.com/googlefinance/disclaimer/) and
|
|
107
|
+
[GOOGLEFINANCE limitations](https://support.google.com/docs/answer/3093281?hl=en).
|
|
108
|
+
The Sheets function and this consumer web transport are separate interfaces.
|
|
109
|
+
|
|
110
|
+
### Historical charts
|
|
111
|
+
|
|
112
|
+
The UI's range enum is statically explicit and each range was replayed
|
|
113
|
+
successfully for GOOGL:
|
|
114
|
+
|
|
115
|
+
| Range | Enum | Observed interval seconds | Observed points |
|
|
116
|
+
| --- | --- | --- | --- |
|
|
117
|
+
| `1D` | 1 | 60 | 632 across regular and extended sessions |
|
|
118
|
+
| `5D` | 2 | 1800 | 70 |
|
|
119
|
+
| `1M` | 3 | 86400 | 23 |
|
|
120
|
+
| `6M` | 4 | 86400 | 128 |
|
|
121
|
+
| `YTD` | 5 | 86400 | 209 |
|
|
122
|
+
| `1Y` | 6 | 86400 | 252 |
|
|
123
|
+
| `5Y` | 7 | 604800 | 262 |
|
|
124
|
+
| `MAX` | 8 | 604800 | 1159 |
|
|
125
|
+
|
|
126
|
+
These intervals/counts describe the captured responses and may vary. `MAX`
|
|
127
|
+
does not imply a complete daily trading history. The response's field 4 groups
|
|
128
|
+
session headers and points. Each point is `[DateTime,priceTuple,volume]`.
|
|
129
|
+
DateTime months are one-based, and field 8 contains a UTC-offset message;
|
|
130
|
+
converting to ISO time must apply that offset rather than the execution host's
|
|
131
|
+
time zone. Session codes remain numeric: `1` and `3` were observed for regular
|
|
132
|
+
and extended data in the day capture.
|
|
133
|
+
|
|
134
|
+
Only verified price, time, and volume are normalized for chart points. Other
|
|
135
|
+
price-tuple values vary with the selected chart baseline and remain available
|
|
136
|
+
in `raw`, avoiding an incorrect “percent change” interpretation.
|
|
137
|
+
|
|
138
|
+
## Validation and limits
|
|
139
|
+
|
|
140
|
+
Sixteen offline unit tests cover captured layouts, duplicate suggestions,
|
|
141
|
+
regular/extended separation, zero values, UTC offsets, malformed/missing data,
|
|
142
|
+
the request envelope, blocking, cancellation, and local validation.
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
npx vitest run tests/unit/finance
|
|
146
|
+
GMAPS_LIVE=1 FINANCE_LIVE=1 npx vitest run tests/live/finance.test.ts
|
|
147
|
+
npm run type-check
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
All passed during implementation. Live tests require explicit opt-in and are
|
|
151
|
+
excluded from the ordinary unit suite. Authentication-gated portfolios,
|
|
152
|
+
watchlists, premium research, AI generation, and undocumented tuple fields
|
|
153
|
+
remain outside this client's verified scope.
|
package/docs/finance.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# Google Finance
|
|
2
|
+
|
|
3
|
+
```ts
|
|
4
|
+
import { finance } from 'googlemaps-kit/finance';
|
|
5
|
+
|
|
6
|
+
const market = finance();
|
|
7
|
+
const quote = await market.quote('GOOGL:NASDAQ');
|
|
8
|
+
console.log(quote.name, quote.price, quote.currency, quote.time);
|
|
9
|
+
console.log(quote.extendedMarket);
|
|
10
|
+
|
|
11
|
+
const matches = await market.search('Microsoft');
|
|
12
|
+
const chart = await market.chart('GOOGL:NASDAQ', { range: '1M' });
|
|
13
|
+
console.log(matches.matches, chart.sessions);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Instrument strings use `symbol:exchange`, matching the website's quote URL.
|
|
17
|
+
Objects `{ symbol, exchange }` are also accepted. Charts support `1D`, `5D`,
|
|
18
|
+
`1M`, `6M`, `YTD`, `1Y`, `5Y`, and `MAX`. Their sampling interval and available
|
|
19
|
+
session groups come from Google, not a locally reconstructed price history.
|
|
20
|
+
|
|
21
|
+
Quote results separate regular and extended-session prices and timestamps.
|
|
22
|
+
They also preserve currency, previous close, source-reported time, exchange
|
|
23
|
+
timezone and UTC offset where returned. `delayStatus` is `not-disclosed`;
|
|
24
|
+
the client does not infer that a quote is real-time. Raw positional payloads
|
|
25
|
+
remain available on all results.
|
|
26
|
+
|
|
27
|
+
Configuration accepts `fetch`, `timeoutMs` (default 30 seconds), `language`
|
|
28
|
+
(default `en`) and `userAgent`. The default user agent is the ordinary browser
|
|
29
|
+
used for the successful capture, because Google served an unsupported-device
|
|
30
|
+
page to a generic HTTP client. All methods accept `signal`; requests are not
|
|
31
|
+
automatically retried. `FinanceError` exposes `kind`, HTTP `status`, RPC code
|
|
32
|
+
and `retryAfterMs` where available. A captured missing-instrument status is
|
|
33
|
+
reported with RPC code 5.
|
|
34
|
+
|
|
35
|
+
This is a public quote/search/chart interface, with no API key or browser
|
|
36
|
+
runtime dependency. It does not implement portfolios, account operations,
|
|
37
|
+
AI investment answers, every asset type, fundamentals or exchange-data
|
|
38
|
+
licensing. See Google's [data information](https://www.google.com/googlefinance/disclaimer/)
|
|
39
|
+
and the [protocol research](finance-research.md) for exact contracts, live
|
|
40
|
+
evidence and remaining limits.
|
|
41
|
+
|
|
42
|
+
Run all public-client probes with `npm run test:google-public:live` or Finance
|
|
43
|
+
alone with `GMAPS_LIVE=1 FINANCE_LIVE=1 npx vitest run tests/live/finance.test.ts`.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Gemini consumer web interface
|
|
2
|
+
|
|
3
|
+
Anonymous browser generation actually returned two marker answers during research on October 29, 2026. HTTP bootstrap alone does not establish that generation works. This module keeps the two operations separate.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { geminiWeb } from 'googlemaps-kit/gemini-web';
|
|
7
|
+
|
|
8
|
+
const metadata = await geminiWeb().inspect();
|
|
9
|
+
console.log(metadata.build, metadata.generation); // generation: 'unverified'
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
`inspect()` fetches the public app HTML and reports its build plus the presence of anonymous session/prompt-token fields. It does not expose token values or generate an answer.
|
|
13
|
+
|
|
14
|
+
## Actual generation through a browser
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { geminiWeb } from 'googlemaps-kit/gemini-web';
|
|
18
|
+
|
|
19
|
+
const client = geminiWeb({ page });
|
|
20
|
+
const answer = await client.generate('Explain a binary search in two sentences.');
|
|
21
|
+
console.log(answer.text, answer.conversationUrl);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
`page` is a caller-owned browser Page implementing the exported `GeminiBrowserPage` subset: `url`, `goto`, `content`, and the needed locator methods. A normal Playwright Page implements this interface. No browser package is bundled or required by the package's other methods; the caller supplies and closes its own browser. Use a fresh anonymous context to reproduce the research environment.
|
|
25
|
+
|
|
26
|
+
`generate()` navigates that page to Gemini if necessary, fills the observed text composer and submits with Enter. It uses the page's existing conversation. It returns only after a **new**, prompt-matched model response has nonempty text, `aria-busy="false"`, and the observed completed-response footer. Existing answers, echoed prompts and incomplete responses cannot satisfy the wait. Output is visible plain text with paragraph boundaries, not the original Markdown source. Generation requires this browser adapter; no HTTP-only generation method is claimed.
|
|
27
|
+
|
|
28
|
+
The current anonymous app used `geminiweb-pa.clients6.google.com/v1/processSession` with browser WebChannel/protobuf traffic. Its generation request contained a browser anti-abuse token. The SDK lets the genuine website perform that protocol; it does not manufacture, harvest or replay browser tokens, cookies or account credentials.
|
|
29
|
+
|
|
30
|
+
Configuration accepts `page`, `fetch`, `timeoutMs` (90 seconds by default) and `pollIntervalMs` (500 ms). `generate(prompt, { signal?, timeoutMs? })` supports caller cancellation and an overall deadline. Cancellation stops the SDK's wait and prevents subsequent submission steps; a prompt already submitted to the website may continue generating. Concurrent generations through one client are rejected so responses cannot be mixed. No automatic retries or model-selection options are implemented.
|
|
31
|
+
|
|
32
|
+
Only ordinary anonymous text generation and its observed DOM are verified. Availability varies by device, region and Google policy. Sign-in, consent or access challenges are surfaced. Images, files, connected apps, account history, saved state, paid plans, model identity and API-equivalent quotas are not established by this interface. The app's displayed `Flash-Lite` label is an observation, not a verified model-version guarantee.
|
|
33
|
+
|
|
34
|
+
Google's [Gemini Apps help](https://support.google.com/gemini/answer/13275745?hl=en) describes limited signed-out text features. This consumer website is separate from Google's supported developer Gemini API and its billing. See the [research ledger](./google-ai-books-research.md) for runtime evidence and limitations.
|
|
35
|
+
|
|
36
|
+
Offline tests run with `npx vitest run tests/unit/gemini-web`. Optional network probes are in `tests/live/google-ai-books.test.ts`; set `GMAPS_LIVE=1 GOOGLE_AI_BOOKS_LIVE=1` and run that file explicitly. The browser-generation case additionally requires `GEMINI_PLAYWRIGHT_MODULE` (an installed Playwright module path) and `GEMINI_BROWSER_EXECUTABLE` (the browser executable path). Without them, only Books metadata and Gemini bootstrap are probed.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Gemini, Books, Ads Keyword Planner and Search Console
|
|
2
|
+
|
|
3
|
+
Observed October 29, 2026. Each service has its own evidence boundary. All probes used anonymous public requests or a new browser context. No account credentials, cookies, paid entitlements or existing user sessions were read. Ads probes were read-only; no campaigns, budgets or account settings were changed.
|
|
4
|
+
|
|
5
|
+
## Gemini consumer web
|
|
6
|
+
|
|
7
|
+
| Question | Observed evidence | Outcome |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Is HTTP bootstrap available? | `gemini.google.com/app?hl=en` returned HTTP 200 with current `WIZ_global_data` build/session metadata and no `SNlM0e` field. | Bootstrap implemented; generation remains unverified from this alone. |
|
|
10
|
+
| Is signed-out browser text generation allowed here? | A fresh Chromium 156 context displayed a composer and returned `GEMINI_PUBLIC_PROBE_20261029` and `GEMINI_PROTOCOL_PROBE_20261029` for the two synthetic echo prompts. | Actual anonymous generation observed. |
|
|
11
|
+
| Which current transport is used? | Browser resource and request capture showed `geminiweb-pa.clients6.google.com/v1/processSession`, WebChannel framing and base64/protobuf request data. The generation request included a long browser anti-abuse token. | Transport shape observed; token algorithm, full schema and a working plain-HTTP replay remain unresolved. No token evasion is implemented. |
|
|
12
|
+
| Which DOM identifies completed answers? | `model-response` → `message-content` → `.markdown[aria-busy="false"]`, accompanied by `.response-footer.complete`. User echoes live in separate `user-query` containers. | Verified parser and caller-owned browser adapter implemented. |
|
|
13
|
+
| Does the implemented SDK work beyond inspection? | A separate fresh browser run through `geminiWeb({ page }).generate(...)` returned exactly `GEMINI_SDK_PROBE_20261029`, with a response ID. | Actual SDK generation verified. |
|
|
14
|
+
|
|
15
|
+
REA inventory evidence: `ev_936d2cf1a5b355fb214a409714f31613616df92589bf54e8cad669a0f76d9c9f`. Initial bundle evidence, limited to the app and the general gstatic origin: `ev_3691a13b7b3097660d166432bbacd1c80690ce95955d379af515a3122df11cff` (16 scripts). Expanded evidence including the actually observed `gemini.gstatic.com` origin: `ev_6f400a58e6634b7ace918f4215cffd6c7609bb4625625dbc155b5e608d3a517a` (68 scripts, 3,766,371 AST nodes, no parse failures). The latter resolves the original incomplete CDN boundary.
|
|
16
|
+
|
|
17
|
+
REA statically analyzes captured source; it does not execute it or prove every function ran. Generation was separately observed through real page interaction and model-response DOM. Server-side internals, uncaptured dynamic behavior, signed-in features and underlying model versions remain unknown. Sanitized executed DOM and bootstrap fixture provenance is recorded in `tests/fixtures/gemini-web/README.md`; neither fixture retains account data or anti-abuse tokens.
|
|
18
|
+
|
|
19
|
+
Google's [Gemini Apps help](https://support.google.com/gemini/answer/13275745?hl=en) documents that some signed-out text interactions are available, subject to device and location. These observations do not establish unlimited use, developer API equivalence, paid-model access, image generation, account history or connected-app permissions.
|
|
20
|
+
|
|
21
|
+
## Google Books
|
|
22
|
+
|
|
23
|
+
| Surface | Actual outcome | Implementation |
|
|
24
|
+
| --- | --- | --- |
|
|
25
|
+
| Books v1 `volumes?q=isbn:9780131103627&maxResults=1` | HTTP 429, query quota exceeded for Google's default consumer project. | No successful v1 search client claimed. |
|
|
26
|
+
| Books v1 `volumes/zyTCAlFPjgYC` | Same HTTP 429 quota denial. | No successful v1 retrieval client claimed. |
|
|
27
|
+
| Public `books.google.com/books?id=zyTCAlFPjgYC&hl=en` | HTTP 200 with a regional redirect to books.google.co.in; OpenGraph metadata and an English bibliographic table contained title, two authors, publisher/year, edition, two ISBNs and 384-page length. | Bounded metadata-by-volume-ID client and actual sanitized fixture implemented. |
|
|
28
|
+
|
|
29
|
+
Google's [Books v1 guide](https://developers.google.com/books/docs/v1/using) documents public metadata search/get, API keys, and separately authorized library operations. Documentation of those methods is not evidence that the unauthenticated calls succeeded here. The [Dynamic Links guide](https://developers.google.com/books/docs/dynamic-links) describes preview/viewability links but specifically says its geography-dependent interface is not designed for server-side or offline queries; that surface was not repurposed as a server metadata service.
|
|
30
|
+
|
|
31
|
+
No scanned pages, preview content, full text, purchases or paywalled material were requested. Current implementation is public bibliographic metadata only; query search and broader Books API parity remain unresolved. Fixture provenance is in `tests/fixtures/books/README.md`.
|
|
32
|
+
|
|
33
|
+
## Ads Keyword Planner
|
|
34
|
+
|
|
35
|
+
| Boundary | Actual evidence | Outcome |
|
|
36
|
+
| --- | --- | --- |
|
|
37
|
+
| Consumer UI | `ads.google.com/aw/keywordplanner/home?hl=en` redirected to `accounts.google.com/v3/signin/identifier`, titled Google Ads sign-in. | No anonymous keyword metrics observed. |
|
|
38
|
+
| Read-only Ads API | `googleads.googleapis.com/v26/customers:listAccessibleCustomers` returned HTTP 401 missing authentication. | No account data retrieved and no mutation attempted. |
|
|
39
|
+
| Documented feature mapping | Google's keyword planning docs map keyword ideas, historical metrics and forecasts to `KeywordPlanIdeaService`. | Documented capability, not an executed anonymous equivalent. |
|
|
40
|
+
|
|
41
|
+
The current [access-level policy](https://developers.google.com/google-ads/api/docs/api-policy/access-levels) says developer tokens were sunset on September 9, 2026 and access is managed per Google Cloud project. Its Explorer restrictions explicitly include KeywordPlanIdeaService, so planning requires an appropriate higher access level. Some older generated summaries on Google's OAuth/header pages still mention developer tokens; those summaries are not treated as overriding the newer policy body.
|
|
42
|
+
|
|
43
|
+
[Google Ads authorization](https://developers.google.com/google-ads/api/rest/auth) requires OAuth with `https://www.googleapis.com/auth/adwords`, appropriate customer access, and a manager login-customer-id where applicable. The [keyword planning guide](https://developers.google.com/google-ads/api/docs/keyword-planning/overview) describes the supported operations and tighter rate limits. No authorized planning request, account billing behavior or keyword metric response was executed. No fake anonymous metrics or paid-service replacement is implemented.
|
|
44
|
+
|
|
45
|
+
## Search Console
|
|
46
|
+
|
|
47
|
+
| Boundary | Actual evidence | Outcome |
|
|
48
|
+
| --- | --- | --- |
|
|
49
|
+
| Public UI entry | `search.google.com/search-console?hl=en` returned its public `/search-console/about` page. | Public marketing entry, not property analytics. |
|
|
50
|
+
| Read-only property list | `www.googleapis.com/webmasters/v3/sites` returned HTTP 401 missing authentication. | No private properties, analytics or URL Inspection data retrieved. |
|
|
51
|
+
| Documented authorization | OAuth token plus appropriate property access; readonly scope is `https://www.googleapis.com/auth/webmasters.readonly`, read/write scope is `https://www.googleapis.com/auth/webmasters`. | Access boundary established, not anonymously bypassed. |
|
|
52
|
+
|
|
53
|
+
Google's [authorization guide](https://developers.google.com/webmaster-tools/v1/how-tos/authorizing) requires authenticated requests, and its [overview](https://developers.google.com/webmaster-tools/about) requires appropriate owner/full/read access to managed properties. Public page checks and private Search Console analytics are distinct. No credential flow, property ownership verification, account data extraction or account mutation was performed. Authorized API execution remains unverified and no anonymous equivalent is claimed.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# YouTube and Lens investigation
|
|
2
|
+
|
|
3
|
+
Date: 2026-10-29. Scope: anonymous consumer metadata and search surfaces, plus a
|
|
4
|
+
Lens upload using a synthetic image. No account, subscription, age restriction,
|
|
5
|
+
CAPTCHA, or protected-media gate was bypassed. Browser interception aborted media
|
|
6
|
+
resources, googlevideo hosts and videoplayback paths before they downloaded
|
|
7
|
+
content.
|
|
8
|
+
|
|
9
|
+
## Findings
|
|
10
|
+
|
|
11
|
+
| ID | Evidence and result | Implementation and boundary |
|
|
12
|
+
| --- | --- | --- |
|
|
13
|
+
| YM-01 | Direct watch HTML HTTP 200 for `bC8fvcpocBU`; inline `ytInitialPlayerResponse` had OK playability, metadata, microformat and caption-track records. | `video()` normalizes public metadata and keeps the raw player/initial payloads. It does not request streams. |
|
|
14
|
+
| YM-02 | Direct watch HTML for `dQw4w9WgXc` contained ERROR playability with an unavailable reason; its oEmbed request returned 400. | Restricted/unavailable player states are preserved. No attempt was made to restore access. |
|
|
15
|
+
| YM-03 | Direct `/results?search_query=Google+for+Developers` returned HTTP 200 with `ytInitialData`, classic video/channel renderers, and an opaque continuation. | `search()` parses retained result renderers and anonymous client context. |
|
|
16
|
+
| YM-04 | POST `/youtubei/v1/search?prettyPrint=false` returned HTTP 200 using the discovered continuation and a minimal `context.client`; no fixed key was required. The SDK live continuation test also passed. | `continueSearch()` sends the opaque token and page-provided version/context. Version, language, region and optional visitor data are retained; unrelated client fingerprint fields are omitted. |
|
|
17
|
+
| YM-05 | Direct `/oembed?url=...&format=json` for `bC8fvcpocBU` returned HTTP 200. | `oembed()` returns the complete typed provider object. |
|
|
18
|
+
| YM-06 | A separate public `Google Developers playlist` query returned HTTP 200 with `lockupViewModel`, content type PLAYLIST, collection thumbnails and byline metadata. The legacy `playlistRenderer` was absent. | Current observed playlist lockups are normalized; unobserved legacy playlist renderers are not claimed. |
|
|
19
|
+
| YM-07 | An advertised `/api/timedtext` URL returned HTTP 200 with zero bytes, as did the browser's caption request. | Caption-track metadata is exposed; transcript content is unresolved. Empty content is not treated as proof that captions do not exist. |
|
|
20
|
+
| LM-01 | A Google Images file chooser uploaded a locally created 600x200 PNG with synthetic test text. `/v3/upload?ep=gsbubb...` returned 303 to a Google Search Lens session. | `createSearch()` reproduces multipart transport and returns the issued redirect without loading recognition results. |
|
|
21
|
+
| LM-02 | The resulting Google Search page displayed an unusual-traffic CAPTCHA. | OCR and visual-match schemas remain unverified. Collection stopped at the gate. |
|
|
22
|
+
| LM-03 | Shipped Google Images module UEShwc constructs `/v3/upload`, multipart `encoded_image`, optional `processed_image_dimensions`, file entry point `gsbubb`, URL entry point `gsbubu`, locale, timestamp and viewport parameters. URL images use GET navigation. | Source-derived request and navigation builders are implemented. The URL-image route was not separately exercised. |
|
|
23
|
+
|
|
24
|
+
The official public test video used for successful metadata is Google's own
|
|
25
|
+
[Introducing Google for Developers!](https://www.youtube.com/watch?v=bC8fvcpocBU).
|
|
26
|
+
No video content was downloaded. Fixture descriptions and metadata are retained
|
|
27
|
+
only as necessary for protocol tests.
|
|
28
|
+
|
|
29
|
+
## REA and artifact identity
|
|
30
|
+
|
|
31
|
+
REA analyzed the exact extracted `var ytInitialPlayerResponse = ...` bootstrap
|
|
32
|
+
statement from the successful watch capture as inert JavaScript. Evidence:
|
|
33
|
+
`ev_4c02a4dbd1187f08caba6500b96a4390b215548332b51c130d5ed6fbb7ff9517`.
|
|
34
|
+
The isolated artifact had three graph nodes and complete parsing of that
|
|
35
|
+
statement. This establishes source structure; successful direct HTTP captures
|
|
36
|
+
and the three live SDK tests establish the observed request behavior.
|
|
37
|
+
|
|
38
|
+
For Lens, the observed parent Images script SHA-256 is
|
|
39
|
+
`dc26401f442b86fe1bda52a406505c98e36c9da00fa22642b8dce1d30e2a0d0a`.
|
|
40
|
+
The isolated UEShwc module consists of its first 4,409 source bytes plus the
|
|
41
|
+
original wrapper's closing statement, so it can be parsed independently. REA
|
|
42
|
+
produced evidence
|
|
43
|
+
`ev_17fc2f463bcf07230fa3dfe55975fec04dabac969e31f4efc4fd8437f54063fa`,
|
|
44
|
+
with six graph nodes. It did not execute Google's code or establish that every
|
|
45
|
+
optional mode is available. An attempt to analyze the entire parent script
|
|
46
|
+
exceeded the tool transport limit; conclusions use the focused module instead.
|
|
47
|
+
|
|
48
|
+
REA target discovery evidence
|
|
49
|
+
`ev_2ae58e65ef2494e0cb89c4f859870bf38b4be9067ff20c81523c151252239c09`
|
|
50
|
+
identified the own-launched Google Images page. A passive navigation observation,
|
|
51
|
+
`ev_c6bfab5b5d7ccd686e75a9d28e13406addc88cf9952b3f1db2effd2088132b43`,
|
|
52
|
+
ended when that first browser was closed and did not capture the later upload.
|
|
53
|
+
It is not used as upload evidence. The controlled browser's saved network
|
|
54
|
+
records and the subsequent source inspection supply LM-01 through LM-03.
|
|
55
|
+
|
|
56
|
+
## Parsing and protocol scope
|
|
57
|
+
|
|
58
|
+
YouTube bootstrap extraction balances JSON object braces while respecting string
|
|
59
|
+
escapes and uses JSON.parse; no page JavaScript is evaluated by the SDK. Search
|
|
60
|
+
normalization is restricted to observed main-result and continuation containers,
|
|
61
|
+
with explicit advertising containers excluded. Unknown renderer/data variants
|
|
62
|
+
remain available in raw payloads. Display counts and relative dates remain text,
|
|
63
|
+
so localization is not mistaken for a precise numeric value.
|
|
64
|
+
|
|
65
|
+
The continuation body uses the discovered token and client name/version from
|
|
66
|
+
`ytcfg.set(...).INNERTUBE_CONTEXT.client`, plus available locale/region/visitor
|
|
67
|
+
fields. Its WEB header uses client number 1, as the captured page configuration
|
|
68
|
+
specified. It is an anonymous consumer protocol, not the documented YouTube
|
|
69
|
+
Data API. No hardcoded page API key or credential is shipped.
|
|
70
|
+
|
|
71
|
+
Lens request construction comes from the shipped upload module and the
|
|
72
|
+
successful browser upload. Its fixed viewport values are SDK choices for the
|
|
73
|
+
transport, rather than a claim about a caller's actual device. No image resize,
|
|
74
|
+
OCR geometry, visual-match, product-match, or AI overview schema is inferred
|
|
75
|
+
from the challenged results page.
|
|
76
|
+
|
|
77
|
+
## Coverage checklist
|
|
78
|
+
|
|
79
|
+
| Surface | Status |
|
|
80
|
+
| --- | --- |
|
|
81
|
+
| YouTube public watch metadata and playability | Observed and implemented. |
|
|
82
|
+
| YouTube search and anonymous continuation | Observed, implemented and live-tested. |
|
|
83
|
+
| YouTube video/channel search renderers and current playlist lockups | Observed and implemented. |
|
|
84
|
+
| YouTube oEmbed | Observed, implemented and live-tested. |
|
|
85
|
+
| YouTube caption track metadata | Observed and implemented. |
|
|
86
|
+
| YouTube transcript content | Unresolved: empty timed-text responses. |
|
|
87
|
+
| YouTube protected media, signature decoding, account-only operations | Outside this public metadata implementation. |
|
|
88
|
+
| Lens file upload and issued results redirect | Observed; transport implemented. |
|
|
89
|
+
| Lens URL-image navigation construction | Static evidence; builder implemented. |
|
|
90
|
+
| Lens OCR, visual matches, and result-page parsing | Unresolved behind the observed traffic challenge. |
|
|
91
|
+
|
|
92
|
+
[Google Lens image-search help](https://support.google.com/websearch/answer/1325808?hl=en)
|
|
93
|
+
describes public file and URL workflows. [YouTube embed help](https://support.google.com/youtube/answer/171780?hl=en)
|
|
94
|
+
describes consumer embedding. These sources describe product behavior; the
|
|
95
|
+
request and response contracts above come from the captured consumer surfaces.
|
|
96
|
+
|
|
97
|
+
## Verification
|
|
98
|
+
|
|
99
|
+
`npx vitest run tests/unit/youtube tests/unit/lens` verifies offline parser,
|
|
100
|
+
request-construction, raw-preservation and failure behavior. The opt-in command
|
|
101
|
+
`GMAPS_LIVE=1 npx vitest run tests/live/google-media.test.ts` passed watch metadata,
|
|
102
|
+
oEmbed, and initial search plus continuation. The Lens live upload was performed
|
|
103
|
+
once through the ordinary browser with the synthetic image and stopped at its
|
|
104
|
+
results challenge. Mocked redirect tests do not claim a successful recognition
|
|
105
|
+
response.
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
# Google Search research ledger
|
|
2
|
+
|
|
3
|
+
Observed October 29, 2026. Scope: anonymous public Search HTML, autocomplete, organic links/snippets, related questions/searches, and actual Google AI Overviews. No signed-in account, proxy, CAPTCHA solution or alternate-IP mechanism was used.
|
|
4
|
+
|
|
5
|
+
## Findings
|
|
6
|
+
|
|
7
|
+
| Question | Observation | Status |
|
|
8
|
+
| --- | --- | --- |
|
|
9
|
+
| Can anonymous autocomplete return structured suggestions? | `suggestqueries.google.com/complete/search?client=firefox&q=typescript&hl=en` returned HTTP 200 and a JSON tuple containing the original query, ten suggestion strings, and subtype metadata. | Observed; implemented and live tested. |
|
|
10
|
+
| Does plain Node fetch return Search results? | `www.google.com/search?q=what+is+typescript&hl=en&gl=us` returned HTTP 200, a JavaScript retry/enable-JavaScript interstitial, no `h3` result titles and no recognized result container. | Observed; explicitly classified. |
|
|
11
|
+
| Does normal browser execution resolve that page? | Unmodified headless Chromium 156 executed the page and followed a 302 redirect to `/sorry/index`. The final HTTP 200 page reported unusual traffic and displayed reCAPTCHA, with no result titles. | Observed; explicitly classified. |
|
|
12
|
+
| Can organic titles, URLs and snippets be extracted from current Search markup? | No successful result page was obtained in this environment. A bounded parser handles linked `h3` titles under `#search`/`#rso`, common snippet containers, and basic link decoding. | Experimental structural implementation; current live markup unverified. |
|
|
13
|
+
| Can actual AI Overview text and sources be retrieved? | No overview was returned before the access challenge. The parser supports explicitly labeled semantic regions without generating any content. No private overview request format was established. | Unresolved; no claim of live retrieval or absence. |
|
|
14
|
+
| Can related questions be expanded or fetched separately? | The blocked result page exposed no usable question expansion flow. Only explicitly labeled supplied HTML is parsed. | Expansion protocol unresolved. |
|
|
15
|
+
|
|
16
|
+
## Runtime evidence
|
|
17
|
+
|
|
18
|
+
REA target discovery `ev_c930379ae4d43fe4ea4aeee9f3a4d6204fe81b600ac9ed7bde7b9c57a2afbf5a` observed a Chrome 156 page at Google's `/sorry/index` after the normal Search navigation.
|
|
19
|
+
|
|
20
|
+
REA bundle evidence `ev_e6d7545da32207ae31b9a9fae90991ad7f8d92dbe362c804c220390b2f2a0eba` observed and analyzed seven scripts from that denied page, with no parse failures. This establishes the captured denial page, not the missing Search/AI subsystem. The selected scope was `https://www.google.com` at loopback CDP endpoint `http://127.0.0.1:9341` with a 500 ms observation window.
|
|
21
|
+
|
|
22
|
+
REA's static bundle analysis does not execute JavaScript; browser navigation was performed separately. Its findings do not establish earlier network activity, server-side behavior, string-built endpoints, encrypted configuration, uncaptured origins, or code from an unavailable successful result page. No endpoint inference from the CAPTCHA scripts is used as a Search or AI Overview API.
|
|
23
|
+
|
|
24
|
+
## Fixtures and evidence quality
|
|
25
|
+
|
|
26
|
+
`tests/fixtures/google-search/provenance.json` records capture dates, original SHA-256 digests, transports and sanitization for the actual responses. The saved autocomplete tuple is unchanged. HTML fixtures remove scripts, frames, challenge/form values, event handlers, origin-trial data and tracking values; the network IP is redacted. The meaningful interstitial and unusual-traffic structures are preserved.
|
|
27
|
+
|
|
28
|
+
`structural-search.html` is synthetic. It tests safe handling of the parser's declared HTML contract, including snippets, a semantic overview region, related content and advertisement exclusions. It is deliberately separated from live evidence and does not establish Google's current positive markup. Unknown or incomplete HTML remains `unrecognized`, and an unrecognized overview remains `unverified`.
|
|
29
|
+
|
|
30
|
+
## Official access and pricing
|
|
31
|
+
|
|
32
|
+
Google's current [Custom Search JSON API overview](https://developers.google.com/custom-search/v1/overview) states that the API is closed to new customers and existing customers must transition by January 1, 2027. For existing customers until discontinuation it lists 100 free queries per day, then $5 per 1,000 requests up to 10,000 queries per day. It requires an API key and configured Programmable Search Engine. This implementation does not use that API.
|
|
33
|
+
|
|
34
|
+
Google's [AI features documentation](https://developers.google.com/search/docs/appearance/ai-features) explains that AI Overviews appear selectively and often do not trigger. An empty parser result therefore cannot establish whether an overview was generated for a query. Google's [Search help page](https://support.google.com/websearch/answer/14901683?co=GENIE.Platform%3DDesktop&hl=en) describes the Web filter as excluding AI Overviews, but this investigation did not verify that filter's request parameters or use it as an overview-retrieval mechanism.
|
|
35
|
+
|
|
36
|
+
No documented public method for retrieving Google.com's actual AI Overview text was established by this investigation. A generated response from a different model or product would not establish that result and is not substituted here. The remaining work requires an accessible successful Search response and observed loading/expansion behavior; the current implementation is not full Search or AI Overview protocol parity.
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# Google Search and autocomplete
|
|
2
|
+
|
|
3
|
+
The `googlemaps-kit/google-search` entry point provides anonymous autocomplete and a Search HTML request/parser. Autocomplete worked against Google's public endpoint during research on October 29, 2026. Search returned a JavaScript interstitial in Node and an unusual-traffic challenge in Chromium. Successful organic results, related questions and AI Overview extraction have **not** been verified against a live response.
|
|
4
|
+
|
|
5
|
+
```ts
|
|
6
|
+
import { googleSearch } from 'googlemaps-kit/google-search';
|
|
7
|
+
|
|
8
|
+
const client = googleSearch({ language: 'en', country: 'us' });
|
|
9
|
+
const suggestions = await client.suggest('typescript');
|
|
10
|
+
console.log(suggestions.suggestions);
|
|
11
|
+
|
|
12
|
+
const response = await client.search('what is typescript');
|
|
13
|
+
console.log(response.status, response.organic, response.aiOverview);
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
No API key or additional runtime dependency is required. Public availability does not imply a quota guarantee. The client makes one request per method call, does not retry automatically, and does not solve or bypass challenges.
|
|
17
|
+
|
|
18
|
+
## Response status
|
|
19
|
+
|
|
20
|
+
| `status` | Meaning |
|
|
21
|
+
| --- | --- |
|
|
22
|
+
| `results` | Supported result links or an explicitly labeled overview region were extracted. HTML extraction remains experimental. |
|
|
23
|
+
| `empty` | A recognized Search container includes an explicit no-results message. |
|
|
24
|
+
| `blocked` | HTTP 403/429, a `/sorry/` destination, or a recognized unusual-traffic challenge. |
|
|
25
|
+
| `javascript-required` | An enable-JavaScript interstitial was returned without recognizable result links. |
|
|
26
|
+
| `consent-required` | The response is Google's consent page. |
|
|
27
|
+
| `unrecognized` | The parser cannot establish that the HTML is a supported result page. |
|
|
28
|
+
|
|
29
|
+
`aiOverview.status` is `present` only for an explicitly labeled `AI Overview` region, `blocked` when Search access is denied, and `unverified` otherwise. Missing or unfamiliar markup never becomes an absent overview. The client does not generate substitute text or call Gemini. `text` and `sources` are extracted only from the supplied region; hidden or deferred content is not retrieved.
|
|
30
|
+
|
|
31
|
+
## Methods and options
|
|
32
|
+
|
|
33
|
+
`client.suggest(query, { language?, country?, signal? })` calls `https://suggestqueries.google.com/complete/search?client=firefox`. It returns `{ query, suggestions, raw }`, preserving unknown tuple metadata. Its payload is independent of Search result pages.
|
|
34
|
+
|
|
35
|
+
`client.search(query, { language?, country?, start?, safe?, signal?, includeRawHtml? })` requests `https://www.google.com/search`. `start` must be a nonnegative integer; `safe` is `active` or `off`. It returns the query, final source URL, HTTP status, extraction status, organic links, related content, overview status and warnings. Raw HTML is retained only when requested. `Retry-After`, when present, is available as `retryAfterMs` and is not automatically acted on.
|
|
36
|
+
|
|
37
|
+
`googleSearch({ fetch?, language?, country?, timeoutMs? })` defaults to Node's `fetch`, language `en`, country `us`, and a 20-second deadline covering both response headers and body. Caller cancellation preserves its reason. Other failures throw `GoogleSearchError` with `kind` equal to `http`, `network`, `parse`, or `timeout`.
|
|
38
|
+
|
|
39
|
+
## Supplying HTML
|
|
40
|
+
|
|
41
|
+
```ts
|
|
42
|
+
import { parseGoogleSearchHtml } from 'googlemaps-kit/google-search';
|
|
43
|
+
|
|
44
|
+
const response = parseGoogleSearchHtml(savedHtml, {
|
|
45
|
+
sourceUrl: 'https://www.google.com/search?q=typescript&hl=en',
|
|
46
|
+
});
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
The parser does not execute scripts. Its provisional structural contract recognizes `#search`/`#rso`, linked `h3` result titles, common snippet containers, and explicitly labeled regions for `AI Overview`, `People also ask`, and `Related searches`. Google may use other structures, localization, asynchronous content or experiments. Positive extraction tests use an explicitly synthetic fixture; they establish this parser contract rather than current Google markup. Real captured fixtures establish only autocomplete and the two access-challenge states.
|
|
50
|
+
|
|
51
|
+
Run offline coverage with `npx vitest run tests/unit/google-search`. Run the optional network probes with `GMAPS_LIVE=1 GOOGLE_SEARCH_LIVE=1 npx vitest run tests/live/google-search.test.ts`; the Search probe reports whether it reached results or a recognized challenge. A passing blocked probe does not establish working Search extraction.
|
|
52
|
+
|
|
53
|
+
See [the research ledger](./google-search-research.md) for observations, evidence and remaining gaps.
|