Best practices
Best practices
A collection of recommendations for building reliable, efficient integrations with Forge.
Prefer coordinates over city names where possible
The city parameter is convenient for prototypes but is resolved against a curated gazetteer of roughly 60 major cities (see data & coverage). If you already know your user's precise location, pass lat/lon directly — it's more accurate, works everywhere on Earth, and avoids 404 not_found errors for towns outside the gazetteer. Use /v1/geocode once to resolve a free-text place name to coordinates, then cache and reuse those coordinates.
Cache aggressively
- Geocoding results almost never change — cache
/v1/geocoderesponses indefinitely (or at least for weeks) keyed by the query string. - Current conditions change slowly enough that caching for 5–10 minutes client-side is usually indistinguishable from real time, and dramatically cuts your request volume.
- Forecast data changes even less frequently; a 1-hour cache is reasonable for most consumer-facing apps.
Handle rate limits gracefully
Check X-RateLimit-Remaining on every response and back off before you hit zero, rather than waiting to react to a 429. See rate limits for the full header reference and a retry-with-backoff snippet.
Validate parameters before you send them
Client-side validation of lat (-90..90), lon (-180..180), units (metric or imperial), and days (1..7) avoids burning both a rate-limit slot and a billed credit on a guaranteed 400 invalid_params. For example:
function validateWeatherParams({ lat, lon, units = 'metric', days = 3 }) {
if (lat < -90 || lat > 90) throw new Error('lat must be between -90 and 90');
if (lon < -180 || lon > 180) throw new Error('lon must be between -180 and 180');
if (!['metric', 'imperial'].includes(units)) throw new Error('units must be metric or imperial');
if (days < 1 || days > 7) throw new Error('days must be between 1 and 7');
}
Watch the units quirk
When requesting units=imperial, remember that precip_mm and visibility_km stay metric while temp, feels_like, dew_point, and wind_speed convert. If you're rendering a unified imperial UI, convert those two fields yourself rather than assuming the API did it for you. See data & coverage for details.
Use structured error codes, not messages
Branch your error handling on error.code (for example invalid_params, not_found, rate_limited) rather than parsing error.message strings, which are meant for humans and may be reworded without notice. See the full list in errors.
Keep credentials scoped and rotatable
- Create separate API keys per environment and per service, so a compromised key can be revoked without taking down unrelated systems.
- Never expose a live key in client-side JavaScript, mobile app bundles, or public repositories — proxy requests through your own backend if browser access is required.
- Rotate keys periodically: create the new key, deploy it, confirm traffic has cut over via the dashboard's usage graph, then revoke the old key.
Plan for growth
If you're consistently near your plan's rate limit or monthly quota, upgrade from the dashboard rather than provisioning multiple keys to work around limits, which is a violation of the terms of service and makes usage harder to reason about. See rate limits for plan tiers.