google-maps-api by tivojn/google-maps-api-skill
npx skills add https://github.com/tivojn/google-maps-api-skill --skill google-maps-api这些规则优先于本技能中的所有其他指令:
立即沟通障碍。 当任何 API 调用失败时(403、REQUEST_DENIED、"not enabled" 等),立即停止并用通俗语言告诉用户发生了什么。不要通过网页搜索或其他后备方案静默地绕过。提供通过 Playwright 修复的选项(见下面的"引导式 API 启用"部分)。
生成 HTML 前先询问。 在没有先询问用户的情况下,绝不开始编写 HTML 页面。用户可能只想要文本答案、JSON 输出或快速摘要。请询问:"需要我为此制作一个交互式 HTML 页面,还是文本摘要就够了?"
选择输出格式前先询问。 当用户的请求可以以文本、JSON 或可视化页面形式回答时,询问他们更喜欢哪种。不要假设。
适用于所有 Google Maps Platform REST API 的全功能 CLI 客户端。与基于浏览器的 google-maps 技能不同,此技能直接调用 Google 的 API,以获得快速、结构化的 JSON 响应。涵盖地图、路线、地点、环境和地理空间服务等 20 多个 API。
添加到以下任一位置的 .env 文件中(按顺序搜索):
# 选项 1:项目目录 .env
echo 'GOOGLE_MAPS_API_KEY=your_key_here' >> .env
# 选项 2:主目录 .env
echo 'GOOGLE_MAPS_API_KEY=your_key_here' >> ~/.env
# 选项 3:环境变量
export GOOGLE_MAPS_API_KEY=your_key_here
These rules override all other instructions in this skill:
Communicate blockers immediately. When ANY API call fails (403, REQUEST_DENIED, "not enabled", etc.), STOP and tell the user what happened in plain language. Do NOT silently work around it with web search or other fallbacks. Offer to fix it via Playwright (see "Guided API Enablement" section below).
Ask before generating HTML. NEVER start writing an HTML page without asking the user first. They may just want a text answer, JSON output, or a quick summary. Ask: "Want me to make an interactive HTML page for this, or is a text summary enough?"
Ask before choosing output format. When the user's request could be answered as text, JSON, or a visual page, ask which they prefer. Don't assume.
Full-featured CLI client for every Google Maps Platform REST API. Unlike the browser-based google-maps skill, this skill calls Google's APIs directly for fast, structured JSON responses. Covers 20+ APIs across maps, routes, places, environment, and geospatial services.
广告位招租
在这里展示您的产品或服务
触达数万 AI 开发者,精准高效
在 Google Cloud Console > APIs & Services > Library 中,启用你需要的 API:
| API 名称 | 控制台名称 |
|---|---|
| 地理编码 | Geocoding API |
| 路线 | Routes API |
| 地点 | Places API (New) |
| 海拔 | Elevation API |
| 时区 | Time Zone API |
| 空气质量 | Air Quality API |
| 花粉 | Pollen API |
| 太阳能 | Solar API |
| 天气 | Weather API |
| 地址验证 | Address Validation API |
| 道路 | Roads API |
| 街景 | Street View Static API |
| 静态地图 | Maps Static API |
| 地理位置 | Geolocation API |
| 航拍视图 | Aerial View API |
| 路线优化 | Route Optimization API |
| 地点聚合 | Places Insights API |
~/.claude/skills/google-maps-api/scripts/gmaps.py
无需外部依赖 - 仅使用 Python 标准库(urllib、json、ssl)。
正向地理编码 - 地址转坐标:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geocode "1600 Amphitheatre Parkway, Mountain View, CA"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geocode "Tokyo Tower" --language ja --region jp
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geocode "Paris" --components "country:FR"
反向地理编码 - 坐标转地址:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py reverse-geocode 37.4224 -122.0856
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py reverse-geocode 48.8584 2.2945 --language fr
获取两个地点之间的导航:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "New York, NY" "Boston, MA"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "LAX" "SFO" --mode transit
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "Seattle" "Portland" --alternatives --avoid-tolls
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "A" "D" --waypoints "B" "C"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "Home" "Work" --mode bicycling --units imperial
距离矩阵 - 多个起点/目的地:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py distance-matrix \
--origins "New York" "Boston" \
--destinations "Philadelphia" "Washington DC"
文本搜索 - 通过查询查找地点:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "best pizza in Chicago"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "pharmacy" --location "40.714,-74.006" --radius 1000
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "5-star hotels" --min-rating 4.5 --open-now
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "EV charging" --type "electric_vehicle_charging_station"
附近搜索 - 查找坐标附近的地点:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-nearby 40.7128 -74.0060 --type restaurant --radius 800
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-nearby 34.0522 -118.2437 --type cafe --max-results 5
地点详情 - 地点的完整信息:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py place-details ChIJN1t_tDeuEmsRUsoyG83frY4
自动补全 - 输入提示建议:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py autocomplete "star" --location "37.7749,-122.4194"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py autocomplete "central p" --types "park"
地点照片 - 获取照片 URL:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py place-photo "places/PLACE_ID/photos/PHOTO_REF" --max-width 800
当前状况:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality 40.7128 -74.0060 --health --pollutants
历史数据(最多 30 天):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality-history 40.7128 -74.0060 --hours 48
预报(最多 96 小时):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality-forecast 40.7128 -74.0060
花粉预报(最多 5 天,草/杂草/树):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py pollen 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py pollen 34.0522 -118.2437 --days 5
返回:3 种植物类型和 15 个物种的通用花粉指数(UPI)。
建筑太阳能潜力:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py solar 37.4219 -122.0841
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py solar 37.4219 -122.0841 --quality HIGH
返回:屋顶面积、日照小时数、最佳面板布局、能源/成本估算。
太阳能数据图层(DSM、通量、阴影栅格):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py solar-layers 37.4219 -122.0841 --radius 100
当前状况:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode current
小时预报(最多 240 小时):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode hourly --hours 48
每日预报(最多 10 天):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode daily --days 7
近期历史(最多 24 小时):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode history --hours 12
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py elevation 39.7392 -104.9903
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py elevation --locations "39.7392,-104.9903|36.4555,-116.8666"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py elevation --path "36.578,-118.292|36.606,-118.099" --samples 20
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py timezone 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py timezone 35.6762 139.6503 --language ja
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py validate-address "1600 Amphitheatre Pkwy, Mountain View, CA 94043"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py validate-address "123 Main St" --region US --enable-usps
返回:可投递性判定、更正后的地址、组件级确认、USPS CASS 数据。
贴合道路 - 对齐 GPS 轨迹:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py snap-roads "60.170,-24.942|60.171,-24.941|60.172,-24.940"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py snap-roads "60.170,-24.942|60.172,-24.940" --interpolate
最近道路:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py nearest-roads "60.170,-24.942|60.171,-24.941"
CLI 数据使用(服务器端图像下载,费用 $7/1,000):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py streetview --lat 46.414 --lng 10.013 --heading 90
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py streetview --location "Eiffel Tower, Paris" --size 800x600
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py streetview --pano CAoSLEFGMVFpcE... --output paris_sv.jpg
对于 HTML 页面 — 始终使用直接的 Google Maps 链接代替(零成本,零密钥暴露):
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint={lat},{lng}&heading={heading}&pitch=0&fov=90
详情见下面的"HTML 中的街景"部分。
警告: 请不要使用旧的简写格式 @{lat},{lng},3a,75y,{heading}h,90t — 它不可靠,并且经常打开一个缩放后的世界地图而不是街景。始终使用上面的 map_action=pano 格式。
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py static-map --lat 40.714 --lng -74.006 --zoom 13
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py static-map --center "Tokyo" --maptype satellite --zoom 12
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py static-map --center "NYC" --markers "color:red|40.714,-74.006" --size 800x600
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geolocation
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geolocation --wifi "00:11:22:33:44:55,-65" "66:77:88:99:AA:BB,-72"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py aerial-view check --address "1600 Amphitheatre Pkwy, Mountain View"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py aerial-view render --address "1600 Amphitheatre Pkwy, Mountain View"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py aerial-view get --video-id VIDEO_ID
解决车辆路径问题(VRP):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py route-optimize problem.json --project my-gcp-project
输入 JSON 格式:根据 Google Route Optimization API 规范,{"model": {"shipments": [...], "vehicles": [...]}}。
统计或列出区域内符合筛选条件的地点:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-aggregate --location "40.714,-74.006" --radius 5000 --type restaurant
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-aggregate --location "34.052,-118.244" --type cafe --min-rating 4.0 --insight INSIGHT_PLACES
生成可嵌入的地图 URL(免费,无限制):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode place --query "Eiffel Tower"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode directions --origin "NYC" --destination "Boston"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode streetview --lat 46.414 --lng 10.013
当用户询问位置/地理/环境问题时,使用适当的命令:
| 用户意图 | 命令 |
|---|---|
| "...在哪里?" | geocode |
| "在...的地址是什么?" | reverse-geocode |
| "如何从 A 到 B?" | directions |
| "A 离 B 有多远?" | distance-matrix |
| "查找...附近的餐厅" | places-search 或 places-nearby |
| "...的营业时间是?" | place-details |
| "...的空气质量如何?" | air-quality |
| "今天花粉严重吗?" | pollen |
| "...的天气如何?" | weather |
| "这个地址有效吗?" | validate-address |
| "...的海拔是多少?" | elevation |
| "...的时区是?" | timezone |
| "显示...的地图" | static-map |
| "我能在屋顶安装太阳能板吗?" | solar |
| "优化配送路线" | route-optimize |
| "该区域有多少咖啡店?" | places-aggregate |
重要:生成 HTML 前始终先询问。 在没有用户明确批准的情况下,绝不开始编写 HTML 文件。以文本形式交付结果后,询问:
"需要我将其放入一个可以在浏览器中打开的交互式 HTML 页面吗?默认主题是暖石日出(浅色、暖色调、高级)。"
如果用户同意(或明确要求 HTML/页面/地图),则生成它。如果他们没有回应或说不需要,只需给他们文本/JSON 结果。
默认情况下,生成零密钥的 HTML 页面,使用 Google Maps 嵌入 iframe(output=embed)— 无需 API 密钥,无密钥暴露风险。仅当用户明确请求嵌入无法支持的高级交互功能(自定义标记、折线、聚类等)时,才使用 Maps JavaScript API(<script src="https://maps.googleapis.com/maps/api/js?key=...">)。
使用这些 iframe 格式显示地图 — 它们不需要 API 密钥且免费:
位置/地点地图:
<iframe src="https://maps.google.com/maps?q=Oahu+Hawaii&z=10&output=embed"
width="100%" height="400" style="border:0" allowfullscreen></iframe>
导航地图:
<iframe src="https://maps.google.com/maps?saddr=Los+Angeles+CA&daddr=San+Jose+CA&output=embed"
width="100%" height="400" style="border:0" allowfullscreen></iframe>
参数:
q — 地点名称或地址(URL 编码,空格用 + 代替)saddr / daddr — 导航的起点/目的地z — 缩放级别(1-20,默认约 12)output=embed — 必需,使其可嵌入ll — 可选的中心坐标 lat,lng警告: 请不要在 Google Maps 嵌入 iframe 上使用 loading="lazy"。延迟加载会阻止屏幕外的 iframe 加载,导致首屏以下的地图永久显示为空白。始终省略 loading 属性或使用 loading="eager"。
| 结果类型 | 默认 HTML 元素 |
|---|---|
| 街景 | 直接 Google Maps 链接(map_action=pano)— 在新标签页中打开完整的交互式街景。见"HTML 中的街景"部分。 |
| 导航 | 带有 saddr/daddr + output=embed 的嵌入 iframe |
| 地点搜索 | 带有 q=place+name + output=embed + 信息卡片的嵌入 iframe |
| 附近搜索 | 以位置为中心的嵌入 iframe + 地点卡片 |
| 静态地图 | 带有 q 和 z 的嵌入 iframe(可缩放、可拖动) |
| 天气/空气质量 | 位置的嵌入 iframe + 状况卡片、图标、图表 |
| 海拔 | 海拔剖面图 + 带有路径标记的嵌入 iframe |
| 太阳能 | 建筑位置的嵌入 iframe + 太阳能潜力统计 |
| 旅行计划 | 组合的多部分页面:嵌入 iframe 地图、地点卡片、天气小部件 |
生成 HTML 页面时:
.html 文件(内联 CSS/JS,无外部依赖)output=embed)— HTML 中没有 API 密钥google.maps.StreetViewPanorama 或 Street View JS API。 对于街景,始终使用带有 map_action=pano 的直接 Google Maps 链接。这是一条硬性规则。<script> 标签。 output=embed iframe 方法无需任何 API 密钥即可处理大多数用例。marea-streetview.html、nyc-trip-plan.html)open <file>(macOS)自动在浏览器中打开硬性规则:绝不使用 JavaScript API 或 Embed API 在 HTML 页面中嵌入街景。 这两种方法都会在客户端代码中暴露 API 密钥。相反,始终使用直接的 Google Maps 链接,在用户的浏览器中打开完整的交互式街景体验 — 零成本,零 API 密钥暴露。
直接链接格式(Google Maps URLs API — 可靠):
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint={lat},{lng}&heading={heading}&pitch={pitch}&fov=90
参数:
viewpoint={lat},{lng} — 街景位置的坐标heading — 指南针航向角度(0=北,90=东,180=南,270=西)pitch — 俯仰角(-90=向下,0=水平,90=向上)fov — 视野角度(10-100,默认 90)map_action=pano — 必需 — 明确触发街景全景模式警告: 请不要使用旧的简写格式 @{lat},{lng},3a,75y,{heading}h,{pitch}t — 它不可靠,并且经常无法打开街景,而是显示一个缩放后的世界地图。始终使用 map_action=pano 格式。
示例:
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=40.76545,-73.98115&heading=90&pitch=0&fov=90
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=48.8584,2.2945&heading=180&pitch=0&fov=90
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=46.414,10.013&heading=270&pitch=-5&fov=90
如何在 HTML 页面中实现:
对于独立的街景按钮:
<a href="https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=40.76545,-73.98115&heading=90&pitch=0&fov=90"
target="_blank" rel="noopener noreferrer"
style="display:inline-block; padding:12px 24px; background:#4f46e5; color:white;
border-radius:8px; text-decoration:none; font-weight:600;">
打开街景 →
</a>
对于 JavaScript 函数(例如,在包含多个位置的旅行计划页面中):
function openStreetView(lat, lng, name) {
window.open(
`https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${lat},${lng}&heading=0&pitch=0&fov=90`,
'_blank'
);
}
对于带有上下文的卡片/预览:
<div class="streetview-card">
<div class="sv-preview">
<!-- 可选:使用静态地图或地点照片作为预览缩略图 -->
<div class="sv-overlay">
<span class="sv-icon">🔭</span>
<span>交互式街景</span>
</div>
</div>
<a href="https://www.google.com/maps/@?api=1&map_action=pano&viewpoint={lat},{lng}&heading=0&pitch=0&fov=90"
target="_blank" rel="noopener noreferrer" class="sv-button">
在 Google Maps 中打开 →
</a>
<p class="sv-note">打开完整的 360° 交互式街景 — 平移、缩放和四处走动</p>
</div>
在整合的旅行计划页面中,将之前的 StreetViewPanorama 部分替换为样式化的按钮/链接卡片。用户点击以在新标签页中打开完整的街景 — 他们可以直接从 Google Maps 获得完整的交互式体验。
为什么采用这种方法:
对于多部分请求(旅行计划、位置研究、比较),始终提供生成单个整合 HTML 页面的选项,将所有收集的数据合并到一个交互式仪表板中。用户应该能够在一个地方看到所有内容,而不是滚动浏览终端输出。
一个整合的页面应包含对话期间收集的每一份数据,例如,一个旅行计划页面可能包含:
整合页面的设计原则:
除非用户另有要求,否则所有 HTML 页面默认使用此主题。
配色方案:
#fafaf9(暖米白色)#ffffff 卡片,#f5f5f4 替代表面#e7e5e4(暖石色),#f0eeec(浅分隔线)#1c1917 主要,#57534e 次要,#a8a29e 三级#4f46e5(靛蓝色)搭配 #eef2ff 浅色和 #c7d2fe 中色#059669,琥珀色 #d97706,红色 #dc2626,蓝色 #2563eb排版:
Playfair Display(衬线体,700-900 字重)— 编辑奢华感Inter(无衬线体),带有完整的字体平滑英雄区域: linear-gradient(160deg, #eef2ff, #faf5ff, #fff7ed) — 靛蓝到薰衣草再到桃色
地图: 通过嵌入 iframe 使用默认的 Google Maps 样式。当使用 Maps JS API(选择加入)时,应用浅色自定义样式 — 柔和的石色调,浅蓝色水域 #c9d7e4,绿色公园 #d4e9d4,白色道路
阴影: 微妙的 0 1px 2px rgba(0,0,0,0.04) 基础,悬停时 0 4px 6px
导航栏: 粘性毛玻璃(rgba(255,255,255,0.85) + backdrop-filter: blur(20px)),活动链接下划线动画
交互: 悬停时卡片上移(translateY(-2px)),时间线圆点填充 + 发光环,悬停时步骤缩进,按钮上移并增加阴影
任何嵌入在客户端 HTML/JavaScript 中的 API 密钥都可以通过浏览器开发者工具被用户看到。这对于个人使用来说没问题,但对于服务多个用户的生产应用来说至关重要。
此技能支持三种部署模式,具有不同的安全配置文件:
用户自己的 API 密钥在 .env 中,由 gmaps.py 在本地使用。密钥从不离开机器。
用户机器
├─ .env (GOOGLE_MAPS_API_KEY=...)
├─ gmaps.py → 直接调用 Google API
└─ HTML 页面 → 零密钥嵌入 iframe(首选)或嵌入密钥(可接受)
风险:低 — 这是用户自己机器上的密钥。密钥限制:不需要(或限制为你使用的 API)。最佳实践:即使对于个人使用,也首选零密钥 output=embed iframe 用于 HTML 页面。仅当你需要高级功能(自定义标记、折线、聚类)时才使用 Maps JS API。
用户配置自己的 Google API 密钥。他们控制自己的计费。
你的应用
├─ 用户在应用设置中配置自己的 API 密钥
├─ 密钥存储在用户配置文件中(静态加密)
├─ 用于服务器端数据查询
└─ 前端密钥:用户创建单独的域名限制密钥
风险:低-中 — 这是用户的密钥,他们的计费。重要:生成可共享/可导出的 HTML 页面时,绝不嵌入用户的密钥。改用静态导出(见下面的可共享导出模式)。引导:引导用户完成 GCP 控制台设置和 API 启用(见上面的设置部分)。
用户向你的平台付费。你提供 Google API 密钥。用户绝不能看到它。
架构:双密钥 + 后端代理
┌─────────────────────────────────────────────────────┐
│ 用户浏览器 │
│ │
│ HTML 页面(从 app.yourdomain.com 提供) │
│ ├─ 交互式地图 ← 前端密钥(域名锁定) │
│ ├─ 街景 ← 前端密钥(域名锁定) │
│ └─ 所有数据(天气、地点、导航等) │
│ ↑ 由后端预渲染,浏览器中无密钥 │
│ │
└──────────────────┬────────────────────────────────────┘
│ /api/geocode, /api/directions 等
▼
┌──────────────────────────────────────────────────────┐
│ 你的后端服务器 │
│ │
│ 后端密钥(环境变量,从不发送到浏览器) │
│ ├─ 地理编码、导航、地点、天气等 │
│ ├─ 街景静态 → 返回图像字节 │
│ └─ 所有数据 API 通过你的密钥在服务器端代理 │
│ │
│ 密钥限制方式:服务器 IP 地址 │
│ 即使泄露:也无法从其他 IP 使用 │
└──────────────────┬────────────────────────────────────┘
│
▼
Google Maps Platform
前端密钥(客户端,在 HTML 中):
https://app.yourdomain.com/*后端密钥(服务器端,隐藏):
在此模式下 HTML 页面如何工作:
// 不安全 — 密钥暴露,客户端获取数据:
const service = new google.maps.DirectionsService();
service.route({ origin: 'JFK', destination: 'The Plaza' });
// 安全 — 数据由后端预获取,浏览器中仅渲染地图:
const routeData = /* 由服务器从后端 API 调用注入 */;
const path = google.maps.geometry.encoding.decodePath(routeData.polyline);
new google.maps.Polyline({ path: path, map: map });
https://app.yourdomain.com/*# 后端服务器环境
GOOGLE_MAPS_BACKEND_KEY=AIzaSy...xxx # 仅服务器端,IP 限制
GOOGLE_MAPS_FRONTEND_KEY
Add to your .env file in any of these locations (searched in order):
# Option 1: Project directory .env
echo 'GOOGLE_MAPS_API_KEY=your_key_here' >> .env
# Option 2: Home directory .env
echo 'GOOGLE_MAPS_API_KEY=your_key_here' >> ~/.env
# Option 3: Environment variable
export GOOGLE_MAPS_API_KEY=your_key_here
In Google Cloud Console > APIs & Services > Library, enable the APIs you need:
| API Name | Console Name |
|---|---|
| Geocoding | Geocoding API |
| Routes | Routes API |
| Places | Places API (New) |
| Elevation | Elevation API |
| Time Zone | Time Zone API |
| Air Quality | Air Quality API |
| Pollen | Pollen API |
| Solar | Solar API |
| Weather | Weather API |
| Address Validation | Address Validation API |
| Roads | Roads API |
| Street View | Street View Static API |
| Static Maps | Maps Static API |
| Geolocation | Geolocation API |
| Aerial View | Aerial View API |
| Route Optimization | Route Optimization API |
| Places Aggregate | Places Insights API |
~/.claude/skills/google-maps-api/scripts/gmaps.py
No external dependencies required - uses only Python standard library (urllib, json, ssl).
Forward geocode - address to coordinates:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geocode "1600 Amphitheatre Parkway, Mountain View, CA"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geocode "Tokyo Tower" --language ja --region jp
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geocode "Paris" --components "country:FR"
Reverse geocode - coordinates to address:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py reverse-geocode 37.4224 -122.0856
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py reverse-geocode 48.8584 2.2945 --language fr
Get directions between two locations:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "New York, NY" "Boston, MA"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "LAX" "SFO" --mode transit
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "Seattle" "Portland" --alternatives --avoid-tolls
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "A" "D" --waypoints "B" "C"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py directions "Home" "Work" --mode bicycling --units imperial
Distance matrix - multiple origins/destinations:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py distance-matrix \
--origins "New York" "Boston" \
--destinations "Philadelphia" "Washington DC"
Text search - find places by query:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "best pizza in Chicago"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "pharmacy" --location "40.714,-74.006" --radius 1000
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "5-star hotels" --min-rating 4.5 --open-now
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-search "EV charging" --type "electric_vehicle_charging_station"
Nearby search - find places near coordinates:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-nearby 40.7128 -74.0060 --type restaurant --radius 800
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-nearby 34.0522 -118.2437 --type cafe --max-results 5
Place details - full info for a place:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py place-details ChIJN1t_tDeuEmsRUsoyG83frY4
Autocomplete - type-ahead suggestions:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py autocomplete "star" --location "37.7749,-122.4194"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py autocomplete "central p" --types "park"
Place photo - get photo URL:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py place-photo "places/PLACE_ID/photos/PHOTO_REF" --max-width 800
Current conditions :
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality 40.7128 -74.0060 --health --pollutants
Historical data (up to 30 days):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality-history 40.7128 -74.0060 --hours 48
Forecast (up to 96 hours):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py air-quality-forecast 40.7128 -74.0060
Pollen forecast (up to 5 days, grass/weed/tree):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py pollen 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py pollen 34.0522 -118.2437 --days 5
Returns: Universal Pollen Index (UPI) for 3 plant types and 15 species.
Building solar potential :
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py solar 37.4219 -122.0841
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py solar 37.4219 -122.0841 --quality HIGH
Returns: roof area, sunlight hours, optimal panel layout, energy/cost estimates.
Solar data layers (DSM, flux, shade rasters):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py solar-layers 37.4219 -122.0841 --radius 100
Current conditions :
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode current
Hourly forecast (up to 240 hours):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode hourly --hours 48
Daily forecast (up to 10 days):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode daily --days 7
Recent history (up to 24 hours):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py weather 40.7128 -74.0060 --mode history --hours 12
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py elevation 39.7392 -104.9903
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py elevation --locations "39.7392,-104.9903|36.4555,-116.8666"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py elevation --path "36.578,-118.292|36.606,-118.099" --samples 20
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py timezone 40.7128 -74.0060
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py timezone 35.6762 139.6503 --language ja
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py validate-address "1600 Amphitheatre Pkwy, Mountain View, CA 94043"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py validate-address "123 Main St" --region US --enable-usps
Returns: deliverability verdict, corrected address, component-level confirmation, USPS CASS data.
Snap to roads - align GPS traces:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py snap-roads "60.170,-24.942|60.171,-24.941|60.172,-24.940"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py snap-roads "60.170,-24.942|60.172,-24.940" --interpolate
Nearest roads :
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py nearest-roads "60.170,-24.942|60.171,-24.941"
CLI data use (server-side image download, costs $7/1,000):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py streetview --lat 46.414 --lng 10.013 --heading 90
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py streetview --location "Eiffel Tower, Paris" --size 800x600
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py streetview --pano CAoSLEFGMVFpcE... --output paris_sv.jpg
For HTML pages — ALWAYS use a direct Google Maps link instead (zero cost, zero key exposure):
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint={lat},{lng}&heading={heading}&pitch=0&fov=90
See "Street View in HTML" section below for details.
WARNING: Do NOT use the old shorthand format @{lat},{lng},3a,75y,{heading}h,90t — it is unreliable and often opens a zoomed-out world map instead of Street View. Always use the map_action=pano format above.
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py static-map --lat 40.714 --lng -74.006 --zoom 13
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py static-map --center "Tokyo" --maptype satellite --zoom 12
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py static-map --center "NYC" --markers "color:red|40.714,-74.006" --size 800x600
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geolocation
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py geolocation --wifi "00:11:22:33:44:55,-65" "66:77:88:99:AA:BB,-72"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py aerial-view check --address "1600 Amphitheatre Pkwy, Mountain View"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py aerial-view render --address "1600 Amphitheatre Pkwy, Mountain View"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py aerial-view get --video-id VIDEO_ID
Solve vehicle routing problems (VRP):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py route-optimize problem.json --project my-gcp-project
Input JSON format: {"model": {"shipments": [...], "vehicles": [...]}} per Google Route Optimization API spec.
Count or list places matching filters in an area:
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-aggregate --location "40.714,-74.006" --radius 5000 --type restaurant
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py places-aggregate --location "34.052,-118.244" --type cafe --min-rating 4.0 --insight INSIGHT_PLACES
Generate embeddable map URLs (free, unlimited):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode place --query "Eiffel Tower"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode directions --origin "NYC" --destination "Boston"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode streetview --lat 46.414 --lng 10.013
When the user asks location/geography/environment questions, use the appropriate command:
| User Intent | Command |
|---|---|
| "Where is...?" | geocode |
| "What address is at...?" | reverse-geocode |
| "How do I get from A to B?" | directions |
| "How far is A from B?" | distance-matrix |
| "Find restaurants near..." | places-search or places-nearby |
| "What are the hours for...?" | place-details |
| "What's the air quality in...?" | air-quality |
| "Is the pollen bad today?" | pollen |
| "What's the weather in...?" | weather |
| "Is this address valid?" | validate-address |
| "What's the elevation of...?" | elevation |
| "What timezone is...?" | timezone |
| "Show me a map of..." | static-map |
| "Can I put solar panels on my roof?" | solar |
| "Optimize delivery routes" | route-optimize |
| "How many coffee shops in area?" | places-aggregate |
IMPORTANT: Always ASK before generating HTML. Never start writing an HTML file without the user's explicit approval. After delivering results as text, ask:
"Want me to put this into an interactive HTML page you can open in the browser? Default theme is Warm Stone Sunrise (light, warm-toned, premium)."
If the user says yes (or explicitly asks for HTML/a page/a map), then generate it. If they don't respond or say no, just give them the text/JSON results.
By default, generate zero-key HTML pages using Google Maps embed iframes (output=embed) — no API key needed, no key exposure risk. Only use the Maps JavaScript API (<script src="https://maps.googleapis.com/maps/api/js?key=...">) when the user explicitly requests advanced interactive features (custom markers, polylines, clustering, etc.) that embeds can't support.
Use these iframe formats for maps — they require no API key and are free:
Location/place map:
<iframe src="https://maps.google.com/maps?q=Oahu+Hawaii&z=10&output=embed"
width="100%" height="400" style="border:0" allowfullscreen></iframe>
Directions map:
<iframe src="https://maps.google.com/maps?saddr=Los+Angeles+CA&daddr=San+Jose+CA&output=embed"
width="100%" height="400" style="border:0" allowfullscreen></iframe>
Parameters:
q — place name or address (URL-encoded, use + for spaces)saddr / daddr — origin/destination for directionsz — zoom level (1-20, default ~12)output=embed — required, makes it embeddablell — optional center coordinates lat,lngWARNING: Do NOT use loading="lazy" on Google Maps embed iframes. Lazy loading prevents off-screen iframes from loading, causing maps below the fold to appear permanently blank. Always omit the loading attribute or use loading="eager".
| Result Type | Default HTML Element |
|---|---|
| Street View | Direct Google Maps link (map_action=pano) — opens full interactive Street View in new tab. See "Street View in HTML" section. |
| Directions | Embed iframe with saddr/daddr + output=embed |
| Places search | Embed iframe with q=place+name + output=embed + info cards |
| Nearby search | Embed iframe centered on location + place cards |
| Static map | Embed iframe with q and z (zoomable, draggable) |
| Weather/Air Quality | Embed iframe for location + condition cards, icons, charts |
| Elevation | Elevation profile chart + embed iframe with path markers |
| Solar | Embed iframe for building location + solar potential stats |
| Trip plans | Combined multi-section page: embed iframe maps, place cards, weather widget |
When generating HTML pages:
.html file (inline CSS/JS, no external dependencies)output=embed) for all maps — NO API key in HTMLgoogle.maps.StreetViewPanorama or the Street View JS API in HTML pages. Always use direct Google Maps links with map_action=pano for Street View. This is a hard rule.<script> tag unless the user explicitly requests advanced interactive features. The output=embed iframe approach handles most use cases without any API key.marea-streetview.html, nyc-trip-plan.html)open <file> (macOS) after creationHARD RULE: Never embed Street View using the JavaScript API or Embed API in HTML pages. Both approaches expose the API key in client-side code. Instead, ALWAYS use a direct Google Maps link that opens the full interactive Street View experience in the user's browser — zero cost, zero API key exposure.
Direct link format (Google Maps URLs API — reliable):
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint={lat},{lng}&heading={heading}&pitch={pitch}&fov=90
Parameters:
viewpoint={lat},{lng} — coordinates of the Street View locationheading — compass heading in degrees (0=North, 90=East, 180=South, 270=West)pitch — pitch angle (-90=down, 0=level, 90=up)fov — field of view in degrees (10-100, default 90)map_action=pano — required — explicitly triggers Street View panorama modeWARNING: Do NOT use the old shorthand format @{lat},{lng},3a,75y,{heading}h,{pitch}t — it is unreliable and often fails to open Street View, instead showing a zoomed-out world map. Always use the map_action=pano format.
Examples:
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=40.76545,-73.98115&heading=90&pitch=0&fov=90
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=48.8584,2.2945&heading=180&pitch=0&fov=90
https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=46.414,10.013&heading=270&pitch=-5&fov=90
How to implement in HTML pages:
For a standalone Street View button:
<a href="https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=40.76545,-73.98115&heading=90&pitch=0&fov=90"
target="_blank" rel="noopener noreferrer"
style="display:inline-block; padding:12px 24px; background:#4f46e5; color:white;
border-radius:8px; text-decoration:none; font-weight:600;">
Open Street View →
</a>
For a JavaScript function (e.g., in trip plan pages with many locations):
function openStreetView(lat, lng, name) {
window.open(
`https://www.google.com/maps/@?api=1&map_action=pano&viewpoint=${lat},${lng}&heading=0&pitch=0&fov=90`,
'_blank'
);
}
For a card/preview with context:
<div class="streetview-card">
<div class="sv-preview">
<!-- Optional: use a static map or place photo as preview thumbnail -->
<div class="sv-overlay">
<span class="sv-icon">🔭</span>
<span>Interactive Street View</span>
</div>
</div>
<a href="https://www.google.com/maps/@?api=1&map_action=pano&viewpoint={lat},{lng}&heading=0&pitch=0&fov=90"
target="_blank" rel="noopener noreferrer" class="sv-button">
Open in Google Maps →
</a>
<p class="sv-note">Opens full 360° interactive Street View — pan, zoom, and walk around</p>
</div>
In consolidated trip plan pages , replace the former StreetViewPanorama section with a styled button/link card. The user clicks to open full Street View in a new tab — they get the complete interactive experience directly from Google Maps.
Why this approach:
For multi-part requests (trip plans, location research, comparisons), always offer to generate a single consolidated HTML page that combines ALL collected data into one interactive dashboard. The user should be able to see everything in one stop rather than scrolling through terminal output.
A consolidated page should include every piece of data gathered during the conversation, for example a trip plan page might combine:
Design principles for consolidated pages:
All HTML pages use this theme by default unless the user requests otherwise.
Color palette:
#fafaf9 (warm off-white)#ffffff cards, #f5f5f4 alt surfaces#e7e5e4 (warm stone), #f0eeec (light dividers)#1c1917 primary, #57534e secondary, #a8a29e tertiary#4f46e5 (indigo) with #eef2ff light and #c7d2fe mid#059669, amber #d97706, red #dc2626, blue #2563ebTypography:
Playfair Display (serif, 700-900 weight) — editorial luxury feelInter (sans-serif) with full font-smoothingHero: linear-gradient(160deg, #eef2ff, #faf5ff, #fff7ed) — indigo to lavender to peach
Maps: Default Google Maps style via embed iframes. When using Maps JS API (opt-in), apply light custom style — muted stone tones, soft blue water #c9d7e4, green parks #d4e9d4, white roads
Shadows: Subtle 0 1px 2px rgba(0,0,0,0.04) base, 0 4px 6px on hover
Nav: Sticky frosted glass (rgba(255,255,255,0.85) + backdrop-filter: blur(20px)), active link underline animation
Interactions: Card lift on hover (translateY(-2px)), timeline dot fill + glow ring, step indent on hover, button lift with shadow increase
Any API key embedded in client-side HTML/JavaScript is visible to users via browser DevTools. This is fine for personal use but critical for production apps where you're serving multiple users.
This skill supports three deployment modes with different security profiles:
The user's own API key in .env, used locally by gmaps.py. Key never leaves the machine.
User's Machine
├─ .env (GOOGLE_MAPS_API_KEY=...)
├─ gmaps.py → calls Google APIs directly
└─ HTML pages → zero-key embed iframes (preferred) or key embedded (acceptable)
Risk : Low — it's the user's own key on their own machine. Key restriction : None needed (or restrict to the APIs you use). Best practice : Even for personal use, prefer zero-key output=embed iframes for HTML pages. Only use Maps JS API when you need advanced features (custom markers, polylines, clustering).
Users configure their own Google API key. They control their own billing.
Your App
├─ User configures their own API key in app settings
├─ Key stored in user's profile (encrypted at rest)
├─ Used server-side for data queries
└─ Frontend key: user creates a separate domain-restricted key
Risk : Low-Medium — it's the user's key, their billing. Important : When generating shareable/exportable HTML pages, NEVER embed the user's key. Use static exports instead (see Shareable Export Mode below). Onboarding : Walk users through GCP Console setup and API enablement (see Setup section above).
Users pay your platform. YOU provide the Google API key. Users must NEVER see it.
Architecture: Two-Key + Backend Proxy
┌─────────────────────────────────────────────────────┐
│ User's Browser │
│ │
│ HTML Page (served from app.yourdomain.com) │
│ ├─ Interactive Maps ← Frontend Key (domain-locked) │
│ ├─ Street View ← Frontend Key (domain-locked) │
│ └─ All data (weather, places, directions, etc.) │
│ ↑ pre-rendered from backend, NO key in browser │
│ │
└──────────────────┬────────────────────────────────────┘
│ /api/geocode, /api/directions, etc.
▼
┌──────────────────────────────────────────────────────┐
│ YOUR Backend Server │
│ │
│ Backend Key (env var, never sent to browser) │
│ ├─ Geocoding, Directions, Places, Weather, etc. │
│ ├─ Street View Static → returns image bytes │
│ └─ All data APIs proxied with your key server-side │
│ │
│ Key restricted by: Server IP address │
│ Even if leaked: won't work from other IPs │
└──────────────────┬────────────────────────────────────┘
│
▼
Google Maps Platform
Frontend Key (client-side, in the HTML):
https://app.yourdomain.com/*Backend Key (server-side, hidden):
How HTML pages work in this mode :
// UNSAFE — key exposed, data fetched client-side:
const service = new google.maps.DirectionsService();
service.route({ origin: 'JFK', destination: 'The Plaza' });
// SAFE — data pre-fetched by backend, only map rendering in browser:
const routeData = /* injected by server from backend API call */;
const path = google.maps.geometry.encoding.decodePath(routeData.polyline);
new google.maps.Polyline({ path: path, map: map });
https://app.yourdomain.com/*# Backend server environment
GOOGLE_MAPS_BACKEND_KEY=AIzaSy...xxx # Server-side only, IP-restricted
GOOGLE_MAPS_FRONTEND_KEY=AIzaSy...yyy # Injected into HTML, domain-restricted
When users want to download or share HTML pages (email, Slack, etc.), generate a static export with NO API keys:
| Element | In-App (interactive) | Shareable Export |
|---|---|---|
| Maps | Maps JavaScript API (frontend key) | Maps Embed API <iframe> (free, no key abuse risk) |
| Street View | Direct Google Maps link (no key needed) | Direct Google Maps link (no key needed) |
| Route lines | DirectionsRenderer (frontend key) | Static map image with path overlay (base64) |
| Data (weather, places) | Pre-rendered from backend | Same pre-rendered HTML — no API calls needed |
| API key exposure | Frontend key, domain-locked | No key at all |
To generate embed URLs (free, unlimited):
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode place --query "Marea Restaurant NYC"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode directions --origin "JFK" --destination "The Plaza Hotel NYC"
python3 ~/.claude/skills/google-maps-api/scripts/gmaps.py embed-url --mode streetview --lat 40.76545 --lng -73.98115
| Deployment | Data APIs | Map Rendering | Key Exposure | Shareable |
|---|---|---|---|---|
| Personal CLI | User's key locally | Zero-key embed iframes (default) | None | Yes (no key) |
| Personal CLI (advanced) | User's key locally | Maps JS API (opt-in for polylines, clustering, etc.) | User's own risk | No (key leaks) |
| BYOK (user's key) | User's key on server | User creates frontend key | User's own risk | Static export only |
| Platform key (you pay) | Backend key (IP-locked) | Frontend key (domain-locked) | Safe | Static export only |
When serving multiple users with your key, also implement:
CRITICAL: When ANY command fails, you MUST tell the user immediately. Do NOT silently fall back to web search or other workarounds. The user needs to know what's broken so they can decide how to fix it.
When a command fails, detect the error type and respond accordingly:
GOOGLE_MAPS_API_KEY is set in .env or environmentThis is the PRIMARY response when an API is not enabled. Do not skip this. Do not silently work around it.
When a user's API call fails with 403 , REQUEST_DENIED , or an "API not enabled" error:
"It looks like the [API Name] isn't enabled on your Google Cloud project yet. No worries — I can walk you through enabling it right now in your browser. Want me to go ahead?"
If the user says yes , use Playwright MCP to automate the enablement:
Step 1: Navigate to the specific API's enablement page:
https://console.cloud.google.com/apis/library/[API_ENDPOINT]
Step 2: If a project selector appears, let the user pick their project
(or auto-select if there's only one)
Step 3: Click the "Enable" button
Step 4: Wait for the confirmation (loading spinner → "API enabled" or
the button changes to "Manage")
Step 5: Confirm to the user: "Done! [API Name] is now enabled.
Let me retry your request."
Step 6: Retry the original command automatically
API endpoint URLs for Playwright navigation (use these exact paths):
| API | GCP Library URL path |
|---|---|
| Geocoding | geocoding-backend.googleapis.com |
| Routes | routes-backend.googleapis.com |
| Places (New) | places-backend.googleapis.com |
| Elevation | elevation-backend.googleapis.com |
| Time Zone | timezone-backend.googleapis.com |
| Air Quality | airquality.googleapis.com |
| Pollen | pollen.googleapis.com |
| Solar | solar.googleapis.com |
| Weather | weather.googleapis.com |
| Address Validation | addressvalidation.googleapis.com |
| Roads | roads.googleapis.com |
| Street View Static | street-view-image-backend.googleapis.com |
| Maps Static | static-maps-backend.googleapis.com |
| Maps JavaScript | maps-backend.googleapis.com |
| Maps Embed | maps-embed-backend.googleapis.com |
| Geolocation | geolocation.googleapis.com |
| Aerial View | aerialview.googleapis.com |
| Route Optimization | routeoptimization.googleapis.com |
Full URL pattern: https://console.cloud.google.com/apis/library/[path_from_table]
"No problem! Here's the direct link — just click Enable: [https://console.cloud.google.com/apis/library/API_ENDPOINT]"
"I can enable all the commonly used APIs for you in one pass — Geocoding, Routes, Places, Weather, Elevation, Time Zone, and Maps JavaScript. Want me to set them all up?"
Then loop through each API page via Playwright, clicking Enable on each.
Important notes for Playwright walkthrough :
Most APIs charge per request. Key free/paid tiers:
.env in: CWD, home dir, skill dirWeekly Installs
97
Repository
First Seen
Feb 21, 2026
Security Audits
Installed on
gemini-cli96
amp96
github-copilot96
codex96
opencode96
cursor96
Lark Drive API 使用指南:飞书云文档、Wiki、表格 Token 处理与文件管理
32,299 周安装