Table of contents

How do I handle geolocation and permissions in Playwright?

Handling geolocation and permissions in Playwright is essential for testing location-based features and applications that require specific browser permissions. Playwright provides robust APIs to manage these settings, allowing you to simulate different geographic locations and control browser permissions for comprehensive testing scenarios.

Understanding Geolocation in Playwright

Geolocation handling in Playwright involves setting specific coordinates that the browser will report when a web application requests the user's location. This is particularly useful for testing location-based services, maps applications, and features that depend on geographic positioning.

Setting Up Geolocation

Basic Geolocation Configuration

You can set geolocation at the browser context level, which applies to all pages within that context:

// JavaScript/Node.js
const { chromium } = require('playwright');

async function setupGeolocation() {
  const browser = await chromium.launch();
  const context = await browser.newContext({
    geolocation: { longitude: -122.4194, latitude: 37.7749 }, // San Francisco
    permissions: ['geolocation']
  });

  const page = await context.newPage();
  await page.goto('https://example.com');

  // The page will now report San Francisco coordinates
  await browser.close();
}
# Python
import asyncio
from playwright.async_api import async_playwright

async def setup_geolocation():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        context = await browser.new_context(
            geolocation={"longitude": -122.4194, "latitude": 37.7749},  # San Francisco
            permissions=["geolocation"]
        )

        page = await context.new_page()
        await page.goto("https://example.com")

        # The page will now report San Francisco coordinates
        await browser.close()

asyncio.run(setup_geolocation())

Dynamic Geolocation Updates

You can also update geolocation settings dynamically during test execution:

// JavaScript
async function updateGeolocation() {
  const browser = await chromium.launch();
  const context = await browser.newContext({
    permissions: ['geolocation']
  });

  const page = await context.newPage();

  // Set initial location (New York)
  await context.setGeolocation({ longitude: -74.0060, latitude: 40.7128 });
  await page.goto('https://maps.google.com');

  // Later, update to different location (London)
  await context.setGeolocation({ longitude: -0.1276, latitude: 51.5074 });
  await page.reload();

  await browser.close();
}
# Python
async def update_geolocation():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        context = await browser.new_context(permissions=["geolocation"])

        page = await context.new_page()

        # Set initial location (New York)
        await context.set_geolocation(longitude=-74.0060, latitude=40.7128)
        await page.goto("https://maps.google.com")

        # Later, update to different location (London)
        await context.set_geolocation(longitude=-0.1276, latitude=51.5074)
        await page.reload()

        await browser.close()

Managing Browser Permissions

Common Permission Types

Playwright supports various browser permissions that you can grant or deny:

// JavaScript - Comprehensive permissions setup
const context = await browser.newContext({
  permissions: [
    'geolocation',
    'camera',
    'microphone',
    'notifications',
    'clipboard-read',
    'clipboard-write',
    'persistent-storage',
    'background-sync'
  ]
});
# Python - Comprehensive permissions setup
context = await browser.new_context(
    permissions=[
        "geolocation",
        "camera", 
        "microphone",
        "notifications",
        "clipboard-read",
        "clipboard-write",
        "persistent-storage",
        "background-sync"
    ]
)

Dynamic Permission Management

You can grant or revoke permissions dynamically during test execution:

// JavaScript
async function managePermissions() {
  const browser = await chromium.launch();
  const context = await browser.newContext();
  const page = await context.newPage();

  // Grant geolocation permission
  await context.grantPermissions(['geolocation']);

  // Set geolocation
  await context.setGeolocation({ longitude: -122.4194, latitude: 37.7749 });

  await page.goto('https://example.com');

  // Later, revoke geolocation permission
  await context.clearPermissions();

  // Or grant different permissions
  await context.grantPermissions(['camera', 'microphone']);

  await browser.close();
}
# Python
async def manage_permissions():
    async with async_playwright() as p:
        browser = await p.chromium.launch()
        context = await browser.new_context()
        page = await context.new_page()

        # Grant geolocation permission
        await context.grant_permissions(["geolocation"])

        # Set geolocation
        await context.set_geolocation(longitude=-122.4194, latitude=37.7749)

        await page.goto("https://example.com")

        # Later, revoke geolocation permission
        await context.clear_permissions()

        # Or grant different permissions
        await context.grant_permissions(["camera", "microphone"])

        await browser.close()

Testing Geolocation Features

Verifying Location Detection

Here's how to test that your application correctly handles geolocation:

// JavaScript
async function testGeolocation() {
  const browser = await chromium.launch();
  const context = await browser.newContext({
    geolocation: { longitude: 2.3522, latitude: 48.8566 }, // Paris
    permissions: ['geolocation']
  });

  const page = await context.newPage();
  await page.goto('https://your-app.com');

  // Wait for location to be detected
  await page.waitForSelector('.location-display');

  // Verify the location is correctly displayed
  const locationText = await page.textContent('.location-display');
  expect(locationText).toContain('Paris');

  // Test location accuracy
  const coordinates = await page.evaluate(() => {
    return new Promise((resolve) => {
      navigator.geolocation.getCurrentPosition((position) => {
        resolve({
          latitude: position.coords.latitude,
          longitude: position.coords.longitude
        });
      });
    });
  });

  expect(coordinates.latitude).toBeCloseTo(48.8566, 4);
  expect(coordinates.longitude).toBeCloseTo(2.3522, 4);

  await browser.close();
}

Testing Location-Based Features

When testing applications that depend on user location, you can simulate different scenarios:

// JavaScript - Testing location-based search
async function testLocationBasedSearch() {
  const browser = await chromium.launch();
  const context = await browser.newContext({
    geolocation: { longitude: -73.935242, latitude: 40.730610 }, // New York
    permissions: ['geolocation']
  });

  const page = await context.newPage();
  await page.goto('https://restaurant-finder.com');

  // Click "Find restaurants near me"
  await page.click('[data-testid="find-nearby"]');

  // Wait for results
  await page.waitForSelector('.restaurant-list');

  // Verify results are location-appropriate
  const restaurants = await page.$$eval('.restaurant-item', items => 
    items.map(item => item.textContent)
  );

  // Test moving to different location
  await context.setGeolocation({ longitude: -122.4194, latitude: 37.7749 }); // San Francisco
  await page.click('[data-testid="refresh-location"]');

  await page.waitForSelector('.restaurant-list');
  const newRestaurants = await page.$$eval('.restaurant-item', items => 
    items.map(item => item.textContent)
  );

  // Verify results changed
  expect(newRestaurants).not.toEqual(restaurants);

  await browser.close();
}

Advanced Permission Scenarios

Testing Permission Requests

Test how your application handles permission requests and denials:

// JavaScript
async function testPermissionRequests() {
  const browser = await chromium.launch();
  const context = await browser.newContext(); // No permissions granted initially
  const page = await context.newPage();

  // Listen for permission requests
  page.on('dialog', async dialog => {
    console.log('Permission dialog:', dialog.message());
    await dialog.accept();
  });

  await page.goto('https://your-app.com');

  // Trigger geolocation request
  await page.click('[data-testid="get-location"]');

  // Grant permission when requested
  await context.grantPermissions(['geolocation']);
  await context.setGeolocation({ longitude: -74.0060, latitude: 40.7128 });

  // Verify location was obtained
  await page.waitForSelector('.location-success');

  await browser.close();
}

Testing Multiple Devices and Locations

Simulate different devices in various locations:

# Python
async def test_multiple_locations():
    async with async_playwright() as p:
        browser = await p.chromium.launch()

        # Test locations
        locations = [
            {"name": "New York", "longitude": -74.0060, "latitude": 40.7128},
            {"name": "London", "longitude": -0.1276, "latitude": 51.5074},
            {"name": "Tokyo", "longitude": 139.6503, "latitude": 35.6762}
        ]

        for location in locations:
            context = await browser.new_context(
                geolocation={"longitude": location["longitude"], "latitude": location["latitude"]},
                permissions=["geolocation"]
            )

            page = await context.new_page()
            await page.goto("https://weather-app.com")

            # Wait for location-based content
            await page.wait_for_selector(".weather-location")

            # Verify location-specific content
            location_text = await page.text_content(".weather-location")
            print(f"Testing from {location['name']}: {location_text}")

            await context.close()

        await browser.close()

Best Practices for Geolocation Testing

1. Test Edge Cases

Always test scenarios where geolocation might fail or be unavailable:

// JavaScript
async function testGeolocationEdgeCases() {
  const browser = await chromium.launch();

  // Test with no geolocation permission
  const contextNoPermission = await browser.newContext({
    permissions: [] // No geolocation permission
  });

  const pageNoPermission = await contextNoPermission.newPage();
  await pageNoPermission.goto('https://your-app.com');

  // Test how app handles geolocation denial
  await pageNoPermission.click('[data-testid="get-location"]');
  await pageNoPermission.waitForSelector('.location-error');

  await contextNoPermission.close();

  // Test with invalid coordinates
  const contextInvalid = await browser.newContext({
    geolocation: { longitude: 999, latitude: 999 }, // Invalid coordinates
    permissions: ['geolocation']
  });

  const pageInvalid = await contextInvalid.newPage();
  await pageInvalid.goto('https://your-app.com');

  await contextInvalid.close();
  await browser.close();
}

2. Verify Accuracy Requirements

Test that your application handles location accuracy appropriately:

// JavaScript
async function testLocationAccuracy() {
  const browser = await chromium.launch();
  const context = await browser.newContext({
    geolocation: { longitude: -122.4194, latitude: 37.7749, accuracy: 100 },
    permissions: ['geolocation']
  });

  const page = await context.newPage();
  await page.goto('https://your-app.com');

  const accuracy = await page.evaluate(() => {
    return new Promise((resolve) => {
      navigator.geolocation.getCurrentPosition((position) => {
        resolve(position.coords.accuracy);
      });
    });
  });

  expect(accuracy).toBe(100);

  await browser.close();
}

CLI Commands for Geolocation Testing

When running Playwright tests with geolocation, you can use command-line options:

# Run tests with specific geolocation
npx playwright test --project=chromium --use-device="iPhone 12" --geolocation="40.7128,-74.0060"

# Run tests with geolocation permissions
npx playwright test --project=chromium --permissions=geolocation

Troubleshooting Common Issues

Issue 1: Geolocation Not Working

If geolocation isn't working as expected, ensure you're granting the proper permissions:

// Correct approach
const context = await browser.newContext({
  geolocation: { longitude: -122.4194, latitude: 37.7749 },
  permissions: ['geolocation'] // Don't forget this!
});

Issue 2: Permission Dialogs Not Appearing

When testing permission flows, make sure you're not pre-granting permissions if you want to test the dialog:

// To test permission dialog
const context = await browser.newContext(); // No permissions granted
page.on('dialog', async dialog => {
  // Handle permission dialog
  await dialog.accept();
});

Issue 3: Coordinates Not Updating

If coordinates aren't updating after calling setGeolocation(), try reloading the page or triggering a fresh geolocation request:

// Update location and refresh
await context.setGeolocation({ longitude: -0.1276, latitude: 51.5074 });
await page.reload(); // or trigger a new geolocation request

Integration with Testing Frameworks

Jest Example

// Jest test example
describe('Geolocation Features', () => {
  test('should display nearby restaurants', async () => {
    const context = await browser.newContext({
      geolocation: { longitude: -73.935242, latitude: 40.730610 },
      permissions: ['geolocation']
    });

    const page = await context.newPage();
    await page.goto('https://restaurant-app.com');

    await page.click('[data-testid="find-nearby"]');
    await expect(page.locator('.restaurant-list')).toBeVisible();

    await context.close();
  });
});

Mocha Example

// Mocha test example
describe('Location Services', function() {
  it('should handle location permission denied', async function() {
    const context = await browser.newContext({
      permissions: [] // No geolocation permission
    });

    const page = await context.newPage();
    await page.goto('https://your-app.com');

    await page.click('[data-testid="get-location"]');
    const errorMessage = await page.textContent('.location-error');
    expect(errorMessage).to.contain('Location access denied');

    await context.close();
  });
});

Configuration Files

You can also configure geolocation settings in your Playwright configuration file:

// playwright.config.js
module.exports = {
  use: {
    geolocation: { longitude: -122.4194, latitude: 37.7749 },
    permissions: ['geolocation']
  },
  projects: [
    {
      name: 'chromium-nyc',
      use: { 
        ...devices['Desktop Chrome'],
        geolocation: { longitude: -74.0060, latitude: 40.7128 }, // New York
        permissions: ['geolocation']
      }
    },
    {
      name: 'chromium-london',
      use: { 
        ...devices['Desktop Chrome'],
        geolocation: { longitude: -0.1276, latitude: 51.5074 }, // London
        permissions: ['geolocation']
      }
    }
  ]
};

Managing geolocation and permissions in Playwright enables comprehensive testing of location-based features and permission-dependent functionality. By understanding how to handle browser sessions in Puppeteer and applying similar concepts to Playwright, you can create robust test suites that cover various geographic scenarios and permission states.

For applications that heavily rely on location services, proper geolocation testing ensures your users have a consistent experience regardless of their geographic location. Similarly, when working with authentication in Puppeteer, understanding permission flows becomes crucial for comprehensive testing strategies.

Remember to test both the happy path where permissions are granted and locations are accurate, as well as edge cases where permissions are denied or geolocation services are unavailable. This comprehensive approach will help you build more resilient location-aware applications that gracefully handle various user scenarios and browser restrictions.

Try WebScraping.AI for Your Web Scraping Needs

Looking for a powerful web scraping solution? WebScraping.AI provides an LLM-powered API that combines Chromium JavaScript rendering with rotating proxies for reliable data extraction.

Key Features:

  • AI-powered extraction: Ask questions about web pages or extract structured data fields
  • JavaScript rendering: Full Chromium browser support for dynamic content
  • Rotating proxies: Datacenter and residential proxies from multiple countries
  • Easy integration: Simple REST API with SDKs for Python, Ruby, PHP, and more
  • Reliable & scalable: Built for developers who need consistent results

Getting Started:

Get page content with AI analysis:

curl "https://api.webscraping.ai/ai/question?url=https://example.com&question=What is the main topic?&api_key=YOUR_API_KEY"

Extract structured data:

curl "https://api.webscraping.ai/ai/fields?url=https://example.com&fields[title]=Page title&fields[price]=Product price&api_key=YOUR_API_KEY"

Try in request builder

Related Questions

Get Started Now

WebScraping.AI provides rotating proxies, Chromium rendering and built-in HTML parser for web scraping
Icon