Roads API
Guide to road snapping, nearest roads, and speed limits with Roads API
Roads API
The Roads API allows you to snap GPS coordinates to roads, find nearby roads, and retrieve speed limit information.
Overview
The Roads API provides three main capabilities:
- Snap to Road - Match GPS coordinates to road segments
- Nearest Roads - Find the closest roads to coordinates
- Speed Limits - Get speed limit data for road segments
Snap to Road
Snap GPS coordinates to the nearest road segment. This is useful for cleaning up GPS tracks and matching device locations to actual roads.
Basic Usage
const snapped = await client.roads.snapToRoad(
'12.999,77.673|12.992,77.658|12.985,77.650'
);With Path Enhancement
Enable path enhancement to add intermediate points for better road curvature matching:
const snapped = await client.roads.snapToRoad(
'12.999,77.673|12.992,77.658|12.985,77.650',
true // enhancePath
);Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
points | string | Yes | Pipe-separated lat,lng pairs (max 50 points) |
enhancePath | boolean | No | Add intermediate points for curvature (default: false) |
Response Example
{
status: "OK",
snappedPoints: [
{
latitude: 12.999012,
longitude: 77.673045,
originalIndex: 0
},
{
latitude: 12.992034,
longitude: 77.658012,
originalIndex: 1
}
],
route: {
distance: { text: "2.5 km", value: 2500 },
duration: { text: "8 mins", value: 480 }
}
}Use Cases
- GPS Track Correction: Clean up noisy GPS data from fitness trackers or vehicle telematics
- Route Reconstruction: Reconstruct actual routes traveled from GPS logs
- Navigation Accuracy: Improve location accuracy in navigation apps
Example: Clean GPS Track
async function cleanGPSTrack(gpsPoints) {
// Convert points to pipe-separated string
const pointsString = gpsPoints
.map(p => `${p.lat},${p.lng}`)
.join('|');
// Snap to roads with path enhancement
const snapped = await client.roads.snapToRoad(pointsString, true);
return snapped.snappedPoints.map((point, index) => ({
lat: point.latitude,
lng: point.longitude,
originalPoint: gpsPoints[point.originalIndex]
}));
}
// Usage
const rawGPS = [
{ lat: 12.999, lng: 77.673 },
{ lat: 12.992, lng: 77.658 },
{ lat: 12.985, lng: 77.650 }
];
cleanGPSTrack(rawGPS)
.then(cleaned => console.log('Cleaned track:', cleaned))
.catch(console.error);Nearest Roads
Find the nearest road segments to given coordinates. Useful for identifying which road a vehicle or person is on.
Basic Usage
const nearest = await client.roads.nearestRoads(
'12.999,77.673|12.992,77.658',
'DRIVING',
500 // radius in meters
);Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
points | string | Yes | Pipe-separated lat,lng pairs (max 100 points) |
mode | string | Yes | Travel mode: DRIVING, WALKING, BICYCLING, TRANSIT |
radius | number | No | Search radius in meters (default: 500) |
Response Example
{
status: "OK",
results: [
{
latitude: 12.999012,
longitude: 77.673045,
road_name: "Outer Ring Road",
distance: 15.3, // meters from original point
confidence: 'high'
},
{
latitude: 12.992034,
longitude: 77.658012,
road_name: "Main Road",
distance: 8.7,
confidence: 'high'
}
]
}Use Cases
- Location Context: Determine which road a user is currently on
- Proximity Analysis: Find roads near points of interest
- Fleet Monitoring: Identify roads where vehicles are located
Example: Fleet Vehicle Tracking
async function getVehicleRoadLocation(vehicleLocations) {
const pointsString = vehicleLocations
.map(v => `${v.lat},${v.lng}`)
.join('|');
const nearest = await client.roads.nearestRoads(
pointsString,
'DRIVING',
100 // Look within 100 meters
);
return vehicleLocations.map((vehicle, index) => ({
vehicleId: vehicle.id,
roadName: nearest.results[index]?.road_name || 'Unknown',
distanceFromRoad: nearest.results[index]?.distance || null,
snappedLocation: {
lat: nearest.results[index]?.latitude,
lng: nearest.results[index]?.longitude
}
}));
}
// Usage
const vehicles = [
{ id: 'V001', lat: 12.999, lng: 77.673 },
{ id: 'V002', lat: 12.992, lng: 77.658 }
];
getVehicleRoadLocation(vehicles)
.then(locations => console.log('Vehicle locations:', locations))
.catch(console.error);Speed Limits
Retrieve speed limit information for road segments.
Basic Usage
const speeds = await client.roads.speedLimits(
'13.063,77.593|13.063,77.593'
);With Custom Snap Strategy
const speeds = await client.roads.speedLimits(
'13.063,77.593|13.063,77.593',
'nearestroad' // or 'snaptoroad'
);Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
points | string | Yes | Pipe-separated lat,lng pairs (max 50 points) |
snapStrategy | string | No | Snapping method: snaptoroad, nearestroad (default: snaptoroad) |
Response Example
{
status: "OK",
speedLimits: [
{
latitude: 13.063012,
longitude: 77.593045,
speed_limit: 60,
unit: 'km/h',
road_name: "NH44",
confidence: 'high'
},
{
latitude: 13.063015,
longitude: 77.593050,
speed_limit: 40,
unit: 'km/h',
road_name: "Service Road",
confidence: 'medium'
}
]
}Use Cases
- Fleet Safety: Monitor and enforce speed compliance
- Navigation: Provide speed limit warnings to drivers
- Insurance Telematics: Calculate risk scores based on speeding behavior
- Route Planning: Optimize routes based on speed limits
Example: Fleet Speed Monitoring
async function checkFleetSpeedCompliance(vehicleRoutes) {
const allSpeeds = [];
for (const route of vehicleRoutes) {
const pointsString = route.path
.map(p => `${p.lat},${p.lng}`)
.join('|');
const speeds = await client.roads.speedLimits(pointsString);
allSpeeds.push({
vehicleId: route.vehicleId,
speedData: speeds.speedLimits
});
}
// Analyze compliance
return allSpeeds.map(vehicle => ({
vehicleId: vehicle.vehicleId,
totalPoints: vehicle.speedData.length,
violations: vehicle.speedData.filter(s => s.speed_limit < 40).length,
averageSpeedLimit: vehicle.speedData.reduce((sum, s) => sum + s.speed_limit, 0) / vehicle.speedData.length
}));
}Advanced Examples
Delivery Route Validation
Validate that delivery drivers followed the expected route:
async function validateDeliveryRoute(expectedRoute, actualGPSPoints) {
// Snap actual GPS points to roads
const pointsString = actualGPSPoints
.map(p => `${p.lat},${p.lng}`)
.join('|');
const snapped = await client.roads.snapToRoad(pointsString, true);
// Calculate deviation from expected route
const deviations = snapped.snappedPoints.map((point, idx) => {
const expected = expectedRoute[idx];
if (!expected) return null;
const distance = calculateDistance(
point.latitude, point.longitude,
expected.lat, expected.lng
);
return {
pointIndex: idx,
deviation: distance
};
});
const avgDeviation = deviations
.filter(d => d !== null)
.reduce((sum, d) => sum + d.deviation, 0) / deviations.length;
return {
isValid: avgDeviation < 50, // Within 50 meters
averageDeviation: avgDeviation,
deviations: deviations
};
}Running Analysis
Analyze running or cycling routes:
async function analyzeRunningRoute(gpsTrack) {
// Snap to roads/paths
const snapped = await client.roads.snapToRoad(
gpsTrack.map(p => `${p.lat},${p.lng}`).join('|'),
true
);
// Get speed limits (for road portions)
const speeds = await client.roads.speedLimits(
gpsTrack.map(p => `${p.lat},${p.lng}`).join('|')
);
return {
totalDistance: snapped.route.distance.value,
estimatedTime: snapped.route.duration.value,
roadSegments: speeds.speedLimits.length,
path: snapped.snappedPoints
};
}Error Handling
Handle common errors:
try {
const snapped = await client.roads.snapToRoad(pointsString);
console.log('Snapped successfully:', snapped);
} catch (error) {
if (error.message.includes('Maximum 50 points')) {
// Split into multiple requests
const chunks = splitIntoChunks(points, 50);
const results = await Promise.all(
chunks.map(chunk =>
client.roads.snapToRoad(chunk.map(p => `${p.lat},${p.lng}`).join('|'))
)
);
console.log('Batch processed:', results);
} else if (error.message.includes('No roads found')) {
console.warn('No roads near the specified coordinates');
} else {
console.error('Roads API error:', error);
}
}
function splitIntoChunks(array, chunkSize) {
const chunks = [];
for (let i = 0; i < array.length; i += chunkSize) {
chunks.push(array.slice(i, i + chunkSize));
}
return chunks;
}Best Practices
1. Batch Processing
For large datasets, process in batches:
async function processLargeTrack(gpsPoints) {
const MAX_POINTS = 50;
const results = [];
for (let i = 0; i < gpsPoints.length; i += MAX_POINTS) {
const chunk = gpsPoints.slice(i, i + MAX_POINTS);
const pointsString = chunk.map(p => `${p.lat},${p.lng}`).join('|');
const snapped = await client.roads.snapToRoad(pointsString, true);
results.push(snapped);
// Add small delay to avoid rate limiting
await new Promise(resolve => setTimeout(resolve, 100));
}
// Merge results
return mergeResults(results);
}2. Cache Results
Cache frequently accessed road data:
const cache = new Map();
async function getCachedSpeedLimits(locationKey, pointsString) {
if (cache.has(locationKey)) {
return cache.get(locationKey);
}
const speeds = await client.roads.speedLimits(pointsString);
cache.set(locationKey, speeds);
// Clear cache after 1 hour
setTimeout(() => cache.delete(locationKey), 3600000);
return speeds;
}3. Validate Coordinates
Ensure coordinates are valid before making requests:
function isValidCoordinate(lat, lng) {
return (
typeof lat === 'number' &&
typeof lng === 'number' &&
lat >= -90 && lat <= 90 &&
lng >= -180 && lng <= 180
);
}
async function safeSnapToRoad(points) {
const validPoints = points.filter(p => isValidCoordinate(p.lat, p.lng));
if (validPoints.length === 0) {
throw new Error('No valid coordinates provided');
}
const pointsString = validPoints
.map(p => `${p.lat},${p.lng}`)
.join('|');
return client.roads.snapToRoad(pointsString);
}Limitations
- Snap to Road: Maximum 50 points per request
- Nearest Roads: Maximum 100 points per request
- Speed Limits: Maximum 50 points per request
- Rate Limits: Subject to your API plan's rate limits
Next Steps
- Learn about Geofencing API for geographic boundaries
- Explore Elevation API for terrain data
- Check Examples for more use cases