Skip to content

Instantly share code, notes, and snippets.

@MrOplus
Created November 25, 2025 07:26
Show Gist options
  • Select an option

  • Save MrOplus/6c203d564e33026e1beba82c102a8bbb to your computer and use it in GitHub Desktop.

Select an option

Save MrOplus/6c203d564e33026e1beba82c102a8bbb to your computer and use it in GitHub Desktop.
Google Maps to Waze Intent (Cloudflare Workers)
export default {
async fetch(request, env, ctx) {
return handleRequest(request);
}
};
async function handleRequest(request) {
const url = new URL(request.url);
const pathname = url.pathname;
if (pathname === '/test' || pathname.startsWith('/test/')) {
const testUrl = pathname === '/test'
? 'https:
: pathname.substring(6);
const coords = await extractCoordinatesFromGoogleMapsUrl(testUrl);
return new Response(
JSON.stringify({
testUrl: testUrl,
coordinates: coords,
success: coords !== null
}, null, 2),
{
status: 200,
headers: { 'Content-Type': 'application/json' }
}
);
}
if (pathname === '/' || pathname === '') {
return new Response(
`<!DOCTYPE html>
<html>
<head>
<title>Google Maps to Waze Converter</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Instantly convert any Google Maps location to Waze navigation. Supports shortened URLs, coordinates, and automatic mobile redirection.">
<!-- Open Graph / Facebook -->
<meta property="og:type" content="website">
<meta property="og:url" content="${url.origin}/">
<meta property="og:title" content="Google Maps to Waze Converter">
<meta property="og:description" content="Instantly convert any Google Maps location to Waze navigation. Supports shortened URLs, coordinates, and automatic mobile redirection.">
<meta property="og:site_name" content="Maps to Waze">
<!-- Twitter -->
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:url" content="${url.origin}/">
<meta name="twitter:title" content="Google Maps to Waze Converter">
<meta name="twitter:description" content="Instantly convert any Google Maps location to Waze navigation. Supports shortened URLs, coordinates, and automatic mobile redirection.">
<!-- Additional Meta Tags -->
<meta name="author" content="Claigrid">
<meta name="keywords" content="google maps, waze, navigation, converter, url shortener, maps, directions">
<meta name="theme-color" content="#000000">
<style>
body {
font-family: system-ui, -apple-system, sans-serif;
max-width: 900px;
margin: 0 auto;
padding: 20px;
line-height: 1.6;
background: #f5f5f5;
color: #222;
}
.container {
background: white;
padding: 30px;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
h1 {
color: #000;
margin-top: 0;
display: flex;
align-items: center;
gap: 10px;
font-weight: 700;
}
h2 {
color: #222;
border-bottom: 2px solid #333;
padding-bottom: 8px;
margin-top: 30px;
font-weight: 600;
}
code {
background: #f4f4f4;
padding: 3px 8px;
border-radius: 4px;
font-size: 0.9em;
color: #333;
border: 1px solid #ddd;
word-break: break-all;
}
.example {
background: #fafafa;
padding: 15px 20px;
margin: 15px 0;
border-radius: 8px;
border-left: 4px solid #333;
border: 1px solid #e0e0e0;
}
.example strong {
color: #000;
display: block;
margin-bottom: 8px;
font-weight: 600;
}
.feature {
background: #f8f8f8;
padding: 15px 20px;
margin: 15px 0;
border-radius: 8px;
border-left: 4px solid #666;
border: 1px solid #e0e0e0;
}
.feature-title {
font-weight: 600;
color: #000;
margin-bottom: 5px;
}
a {
color: #000;
text-decoration: underline;
text-decoration-color: #999;
}
a:hover {
text-decoration-color: #000;
}
.badge {
display: inline-block;
background: #333;
color: white;
padding: 4px 12px;
border-radius: 20px;
font-size: 0.85em;
font-weight: 500;
margin-left: 10px;
}
.badge.mobile { background: #555; }
.badge.desktop { background: #666; }
ul {
margin: 10px 0;
padding-left: 20px;
}
li {
margin: 8px 0;
color: #333;
}
.highlight {
background: #f0f0f0;
padding: 15px 20px;
border-radius: 8px;
border: 2px solid #333;
margin: 20px 0;
}
.grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
gap: 15px;
margin: 20px 0;
}
.grid-item {
background: #fafafa;
padding: 15px;
border-radius: 8px;
border: 1px solid #ddd;
}
.grid-item strong {
color: #000;
display: block;
margin-bottom: 8px;
font-weight: 600;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
th {
padding: 12px;
text-align: left;
border: 1px solid #ddd;
background: #f5f5f5;
font-weight: 600;
color: #000;
}
td {
padding: 10px;
border: 1px solid #ddd;
}
tr:nth-child(even) {
background: #fafafa;
}
small {
color: #666;
}
</style>
</head>
<body>
<div class="container">
<h1>
🗺️ Google Maps to Waze Converter
<span class="badge">v2.0</span>
</h1>
<p style="font-size: 1.1em; color: #555;">
Instantly convert any Google Maps location to Waze navigation with automatic mobile redirection
</p>
<h2>🚀 Quick Start</h2>
<div class="highlight">
<strong>📱 On Mobile:</strong> Automatic redirect to Waze app<br>
<strong>💻 On Desktop:</strong> Get a Waze URL to open on your phone
</div>
<h2>📍 Supported Formats</h2>
<div class="example">
<strong>🔗 Shortened Google Maps URLs</strong>
Just paste the short code after your worker URL:<br><br>
<code>${url.origin}/UwxS8G7nwq9Zk5mp9</code><br><br>
<small>Works with maps.app.goo.gl links - just copy the code!</small>
</div>
<div class="example">
<strong>🌐 Full Google Maps URLs</strong>
Copy any Google Maps URL and add it to the path:<br><br>
<code>${url.origin}/https:
<code>${url.origin}/https:
</div>
<div class="example">
<strong>📌 Direct Coordinates</strong>
Quick format for known coordinates:<br><br>
<code>${url.origin}/@35.7402314,51.3325282</code><br>
<code>${url.origin}/35.7402314,51.3325282</code><br>
<code>${url.origin}/q=35.7402314,51.3325282</code>
</div>
<h2>✨ Supported Google Maps Formats</h2>
<div class="grid">
<div class="grid-item">
<strong>Short Codes</strong>
<code>/abc123xyz</code>
</div>
<div class="grid-item">
<strong>@ Pattern</strong>
<code>@lat,lng,zoom</code>
</div>
<div class="grid-item">
<strong>Place Format</strong>
<code>/place/lat,lng/</code>
</div>
<div class="grid-item">
<strong>Data Parameters</strong>
<code>3d...!4d...</code>
</div>
<div class="grid-item">
<strong>Query Params</strong>
<code>?q=lat,lng</code>
</div>
<div class="grid-item">
<strong>Directions</strong>
<code>/dir
</div>
</div>
<h2>💡 How It Works</h2>
<div class="feature">
<div class="feature-title">1. Automatic URL Expansion</div>
Shortened Google Maps URLs (maps.app.goo.gl) are automatically expanded to extract coordinates
</div>
<div class="feature">
<div class="feature-title">2. Smart Coordinate Detection</div>
Supports multiple Google Maps coordinate formats including @ patterns, place URLs, and data parameters
</div>
<div class="feature">
<div class="feature-title">3. Device-Aware Redirect</div>
Mobile devices get instant Waze navigation, desktop users get a shareable Waze link
</div>
<h2>📝 Usage Examples</h2>
<div class="example">
<strong>Example 1: Share Location from Google Maps</strong>
<ul>
<li>Open Google Maps on your phone</li>
<li>Tap "Share" on any location</li>
<li>Copy the link (looks like: <code>maps.app.goo.gl/xyz123</code>)</li>
<li>Extract just the code: <code>xyz123</code></li>
<li>Visit: <code>${url.origin}/xyz123</code></li>
<li>✅ Opens in Waze automatically!</li>
</ul>
</div>
<div class="example">
<strong>Example 2: From Browser</strong>
<ul>
<li>Find a location in Google Maps on desktop</li>
<li>Copy the URL from address bar</li>
<li>Add it after your worker URL</li>
<li>Send to your phone</li>
<li>✅ One-tap Waze navigation!</li>
</ul>
</div>
<h2>🔧 Technical Details</h2>
<p>This Cloudflare Worker:</p>
<ul>
<li>✅ Extracts coordinates from 10+ different Google Maps URL formats</li>
<li>✅ Follows redirects for shortened URLs</li>
<li>✅ Detects mobile devices (Android, iOS)</li>
<li>✅ Generates proper Waze deep links (<code>waze.com/ul?ll=...</code>)</li>
<li>✅ Works worldwide with any coordinates</li>
<li>✅ Zero data storage - instant processing</li>
</ul>
<h2>🎯 URL Formats Reference</h2>
<table>
<thead>
<tr>
<th>Google Maps Format</th>
<th>Worker URL</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>maps.app.goo.gl/UwxS8G7nwq9Zk5mp9</code></td>
<td><code>${url.origin}/UwxS8G7nwq9Zk5mp9</code></td>
</tr>
<tr>
<td><code>@35.74,51.33,15z</code></td>
<td><code>${url.origin}/@35.74,51.33</code></td>
</tr>
<tr>
<td><code>/place/35.74,51.33/</code></td>
<td><code>${url.origin}/place/Name/@35.74,51.33</code></td>
</tr>
<tr>
<td><code>?q=35.74,51.33</code></td>
<td><code>${url.origin}/q=35.74,51.33</code></td>
</tr>
</tbody>
</table>
<div style="margin-top: 40px; padding-top: 20px; border-top: 2px solid #e0e0e0; color: #666; font-size: 0.9em;">
<p><strong>Need help?</strong> If a URL format doesn't work, open the Google Maps link in your browser first, then copy the full expanded URL.</p>
<p><strong>Privacy:</strong> No data is stored. All processing happens in real-time on Cloudflare's edge network.</p>
</div>
</div>
</body>
</html>`,
{
status: 200,
headers: { 'Content-Type': 'text/html; charset=utf-8' }
}
);
}
try {
const coordinates = await extractCoordinatesFromPath(pathname, url);
if (!coordinates) {
const isShortUrl = pathname.includes('goo.gl') || pathname.includes('maps.app.goo.gl');
return new Response(
JSON.stringify({
error: 'Could not extract coordinates from URL',
providedPath: pathname,
isShortUrl: isShortUrl,
usage: 'Use formats like: /@37.7749,-122.4194 or /37.7749,-122.4194',
note: isShortUrl ? 'Shortened URL detected. Please open the URL first in a browser to get the full Google Maps URL with coordinates, then use that URL.' : 'Could not find coordinates in the provided URL'
}),
{
status: 400,
headers: { 'Content-Type': 'application/json' }
}
);
}
const wazeUrl = generateWazeUrl(coordinates);
const userAgent = request.headers.get('User-Agent') || '';
const isMobile = /Android|iPhone|iPad|iPod/i.test(userAgent);
if (isMobile) {
return Response.redirect(wazeUrl, 302);
}
return new Response(
`<!DOCTYPE html>
<html>
<head>
<title>Open in Waze</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: system-ui, sans-serif; max-width: 600px; margin: 40px auto; padding: 20px; text-align: center; }
.coordinates { font-size: 24px; font-weight: bold; color: #333; margin: 20px 0; }
.button { display: inline-block; background: #00d4ff; color: white; padding: 15px 30px; text-decoration: none; border-radius: 8px; font-size: 18px; margin: 20px 0; }
.button:hover { background: #00b8e6; }
.info { color: #666; margin-top: 30px; }
code { background: #f4f4f4; padding: 2px 6px; border-radius: 3px; }
</style>
</head>
<body>
<h1>🗺️ Navigate with Waze</h1>
<div class="coordinates">${coordinates.latitude}, ${coordinates.longitude}</div>
<a href="${wazeUrl}" class="button">Open in Waze</a>
<div class="info">
<p>Click the button above to open this location in Waze</p>
<p><small>Or copy this URL: <code>${wazeUrl}</code></small></p>
</div>
</body>
</html>`,
{
status: 200,
headers: { 'Content-Type': 'text/html; charset=utf-8' }
}
);
} catch (error) {
return new Response(
JSON.stringify({
error: 'Failed to process URL',
details: error.message
}),
{
status: 500,
headers: { 'Content-Type': 'application/json' }
}
);
}
}
async function extractCoordinatesFromPath(pathname, url) {
try {
if (pathname.startsWith('/http:
let embeddedUrl = pathname.substring(1);
if (url.search) {
if (embeddedUrl.includes('?')) {
embeddedUrl += '&' + url.search.substring(1);
} else {
embeddedUrl += url.search;
}
}
return await extractCoordinatesFromGoogleMapsUrl(embeddedUrl);
}
let match = pathname.match(/@(-?\d+\.?\d*),(-?\d+\.?\d*)(?:,\d+\.?\d*z?)?/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
match = pathname.match(/^\/(-?\d+\.?\d*),(-?\d+\.?\d*)$/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
match = pathname.match(/\/q=(-?\d+\.?\d*),(-?\d+\.?\d*)/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
match = pathname.match(/\/place\/[^/]+\/@(-?\d+\.?\d*),(-?\d+\.?\d*)/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
const shortCodeMatch = pathname.match(/^\/([a-zA-Z0-9]{10,20})$/);
if (shortCodeMatch) {
const shortCode = shortCodeMatch[1];
const fullShortUrl = `https:
return await extractCoordinatesFromGoogleMapsUrl(fullShortUrl);
}
if (pathname.includes('google.com/maps') || pathname.includes('maps.app.goo.gl') || pathname.includes('goo.gl')) {
let embeddedUrl = pathname.substring(1);
if (!embeddedUrl.startsWith('http')) {
embeddedUrl = 'https:
}
if (url.search) {
if (embeddedUrl.includes('?')) {
embeddedUrl += '&' + url.search.substring(1);
} else {
embeddedUrl += url.search;
}
}
return await extractCoordinatesFromGoogleMapsUrl(embeddedUrl);
}
const qParam = url.searchParams.get('q');
if (qParam) {
match = qParam.match(/^(-?\d+\.?\d*),\s*(-?\d+\.?\d*)$/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
}
return null;
} catch (error) {
return null;
}
}
async function extractCoordinatesFromGoogleMapsUrl(urlString) {
try {
if (urlString.includes('/sorry/index')) {
try {
const url = new URL(urlString);
const continueParam = url.searchParams.get('continue');
if (continueParam) {
const decodedContinue = decodeURIComponent(continueParam);
return await extractCoordinatesFromGoogleMapsUrl(decodedContinue);
}
} catch (e) {
}
}
if (urlString.includes('maps.app.goo.gl') || urlString.includes('goo.gl')) {
const expandedUrl = await expandShortUrl(urlString);
if (expandedUrl && expandedUrl !== urlString) {
urlString = expandedUrl;
if (expandedUrl.includes('/sorry/index')) {
return await extractCoordinatesFromGoogleMapsUrl(expandedUrl);
}
} else {
}
}
let match = urlString.match(/@(-?\d+\.?\d*),(-?\d+\.?\d*)(?:,\d+\.?\d*z?)?/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
match = urlString.match(/\/place\/(-?\d+\.?\d*),(-?\d+\.?\d*)(?:\/|$)/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
match = urlString.match(/\/maps\/search\/(-?\d+\.?\d*),\s*\+?(-?\d+\.?\d*)/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
match = urlString.match(/[!&?]3d(-?\d+\.?\d*)[!&]4d(-?\d+\.?\d*)/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
match = urlString.match(/(?:\/dir\/\/|destination=)(-?\d+\.?\d*),(-?\d+\.?\d*)/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
try {
const url = new URL(urlString);
const qParam = url.searchParams.get('q');
if (qParam) {
match = qParam.match(/^(-?\d+\.?\d*),\s*(-?\d+\.?\d*)$/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
}
const llParam = url.searchParams.get('ll');
if (llParam) {
match = llParam.match(/^(-?\d+\.?\d*),\s*(-?\d+\.?\d*)$/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
}
const centerParam = url.searchParams.get('center');
if (centerParam) {
match = centerParam.match(/^(-?\d+\.?\d*),\s*(-?\d+\.?\d*)$/);
if (match) {
return {
latitude: parseFloat(match[1]),
longitude: parseFloat(match[2])
};
}
}
} catch (e) {
}
return null;
} catch (error) {
return null;
}
}
async function expandShortUrl(shortUrl) {
try {
const response = await fetch(shortUrl, {
method: 'GET',
redirect: 'follow',
headers: {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36'
}
});
const finalUrl = response.url;
if (finalUrl === shortUrl) {
return null;
}
return finalUrl;
} catch (error) {
return null;
}
}
function generateWazeUrl(coordinates) {
const { latitude, longitude } = coordinates;
return `https:
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment