How I Fixed a Geolocation Permission Bug in a Next.js App
Source: Dev.to
While contributing to Accuguide—an open‑source platform that helps people discover accessible places and services—I encountered an annoying bug: the browser asked for location permission on every single page load, even on pages where location data was irrelevant.
The Problem
Visiting any page on Accuguide triggered the prompt:
accuguide.org wants to know your location
- Appeared on pages like
/info/aboutand/legal/privacy. - Caused poor UX and hurt the Lighthouse “Avoids requesting permissions on page load” audit.
- Expected behavior: request location only on the
/searchpage and only when the user has typed a search query.
The location logic lived in a React context LocationProvider (app/contexts/location-context.tsx) with the following effect:
// ❌ The problem
useEffect(() => {
requestLocationPermission()
}, [])
Because LocationProvider wrapped the entire app in the root layout, the effect ran on every page mount.
The Fix
1. Remove the automatic request from the provider
// ✅ Remove this entirely from LocationProvider
useEffect(() => {
requestLocationPermission()
}, [])
Now LocationProvider only supplies the context; it no longer triggers a permission request on its own.
2. Request location only on the search page when needed
In app/search/page.tsx:
import { useSearchParams } from 'next/navigation';
import { useLocation } from '@/contexts/location-context';
import { useEffect } from 'react';
const searchParams = useSearchParams();
const query = searchParams.get('q');
const { requestLocationPermission, location } = useLocation();
useEffect(() => {
if (query && !location) {
requestLocationPermission();
}
}, [query]);
Explanation
query– the search term from the URL (?q=coffee shops).!location– request only if we don’t already have a location.[query]– re‑run the effect only when the query changes.
Outcome
| Aspect | Before | After |
|---|---|---|
| Location prompt | Appeared on every page | Appears only on /search page |
| Trigger condition | On mount (global) | When a query exists on the search page |
| Lighthouse audit | ❌ Fails | ✅ Passes |
| User experience | Confusing, unnecessary prompts | Intuitive, only when needed |
- No more permission prompts on unrelated pages.
- Lighthouse audit now passes the “Avoids requesting permissions on page load” check.
- Users understand why location is needed (they’re performing a search).
Lessons Learned
- Side effects belong where they’re needed. Placing
useEffectcalls in a global provider causes them to run on every render of the provider, which may be far more often than intended. - Ask yourself: “Where does this actually need to happen?” and move the logic to that specific component or page.
- Common pitfalls in React apps include:
- Analytics tracking firing on pages where it isn’t required.
- Cookie‑consent popups appearing multiple times.
- Auth checks running unnecessarily on public pages.
Good vs. Bad Patterns
// ❌ Bad: side effect in a global provider
useEffect(() => {
doSomethingThatShouldOnlyHappenInOnePlace();
}, []);
// ✅ Good: side effect scoped to the right component/page
useEffect(() => {
if (conditionIsRight) {
doSomethingThatShouldOnlyHappenInOnePlace();
}
}, [dependency]);
Conclusion
By moving the location‑request logic out of the global LocationProvider and into the specific search page component, the permission prompt now appears only when truly necessary, improving both user experience and performance metrics.
If you found this helpful, check out the Accuguide repository and my GitHub profile for more examples.