Camera Access in Development: HTTPS Setup Guide

2025-10-06

Camera Access in Development: HTTPS Setup Guide

Modern browsers require HTTPS for camera access due to security policies. Here's how to enable camera access when developing the MTG card scanner locally.

The Problem

When running npm run dev and trying to use the camera scanner, you see errors like:

  • ❌ "Camera access is not supported"
  • πŸ”’ "NotAllowedError: Permission denied"
  • ⚠️ "getUserMedia is not defined"
  • 🚫 "Camera requires HTTPS"

This happens because browsers block camera/microphone access on non-HTTPS connections (except localhost on some browsers).

The Solution

Option 1: Run Development Server with HTTPS (Recommended)

Next.js 14.2+ includes experimental HTTPS support. Use the new dev:https script:

npm run dev:https

This will:

  1. Start Next.js development server with HTTPS enabled
  2. Auto-generate a self-signed certificate
  3. Allow camera access in your browser

First time setup:

When you visit https://localhost:3000, your browser will show a certificate warning because it's self-signed. This is normal and safe for local development.

Chrome/Edge:

  1. Click "Advanced"
  2. Click "Proceed to localhost (unsafe)"

Firefox:

  1. Click "Advanced"
  2. Click "Accept the Risk and Continue"

Safari:

  1. Click "Show Details"
  2. Click "visit this website"

Option 2: Use localhost (Limited Support)

Some browsers allow camera access on http://localhost (but not http://127.0.0.1 or other IPs):

npm run dev
# Visit http://localhost:3000 (not 127.0.0.1)

This works on:

  • βœ… Chrome/Edge on localhost
  • βœ… Firefox on localhost
  • ❌ Safari (requires HTTPS even for localhost)
  • ❌ Mobile browsers (require HTTPS)

Option 3: Upload Images Instead

The scanner supports both camera capture AND image upload. Use the file upload button if camera access isn't working:

  1. Take a photo of your card with your phone
  2. Click "πŸ“ Upload Image" in the scanner
  3. Select the photo from your device

Enhanced Error Messages

The scanner now provides specific guidance based on the error:

// Permission denied
❌ Camera permission denied. Please allow camera access in your browser.

// No camera hardware
πŸ“· No camera found. Please connect a camera or upload an image.

// HTTPS required
πŸ”’ Camera requires HTTPS. In development, run: npm run dev:https

// Generic error
Could not access camera. Please check permissions or upload an image.

Testing on Mobile Devices

To test the camera on your phone during development:

1. Use ngrok for HTTPS Tunneling

# Install ngrok
npm install -g ngrok

# Start your dev server
npm run dev

# In another terminal, create HTTPS tunnel
ngrok http 3000

Visit the https:// URL ngrok provides on your mobile device.

2. Use Your Local Network with HTTPS

# Run with HTTPS
npm run dev:https

# Find your local IP
ipconfig  # Windows
ifconfig  # Mac/Linux

# Visit from mobile
https://192.168.1.XXX:3000

Accept the certificate warning on your mobile device.

Browser Camera Permissions

Granting Camera Access

Chrome/Edge:

  1. Click the camera icon in the address bar
  2. Select "Always allow https://localhost to access your camera"
  3. Reload the page

Firefox:

  1. Click the camera icon in the address bar
  2. Select "Allow" and check "Remember this decision"
  3. Reload the page

Safari:

  1. Safari β†’ Settings β†’ Websites β†’ Camera
  2. Find "localhost" and set to "Allow"

Revoking Camera Access (to Test Errors)

Chrome/Edge:

  1. Settings β†’ Privacy and security β†’ Site settings β†’ Camera
  2. Find localhost and change to "Block"

Firefox:

  1. about:preferences#privacy β†’ Permissions β†’ Camera β†’ Settings
  2. Remove localhost or set to "Block"

Production Considerations

In production behind Caddy/nginx with proper SSL certificates, camera access works automatically because:

  1. βœ… Domain has valid SSL certificate
  2. βœ… Browser trusts the certificate
  3. βœ… HTTPS connection is secure
  4. βœ… Camera API is fully supported

The dev:https script is ONLY needed for local development.

Technical Details

How the HTTPS Dev Server Works

Next.js's --experimental-https flag:

// Internally generates
{
  key: fs.readFileSync('.next/key.pem'),
  cert: fs.readFileSync('.next/cert.pem')
}

Certificates are auto-generated on first run and cached in .next/ directory.

Browser Security Policy

The MediaDevices API requires a "secure context":

// This only works in secure contexts
navigator.mediaDevices.getUserMedia({ video: true })

Secure contexts are:

  • βœ… HTTPS pages (any domain)
  • βœ… http://localhost (Chrome/Firefox only)
  • βœ… http://127.0.0.1 (Chrome/Firefox only)
  • ❌ HTTP pages (any other domain/IP)
  • ❌ File:// protocol

Error Detection in Code

The scanner detects specific camera errors:

try {
  const stream = await navigator.mediaDevices.getUserMedia({ video: true });
} catch (err) {
  if (err.name === 'NotAllowedError') {
    // User denied permission
  } else if (err.name === 'NotFoundError') {
    // No camera hardware
  } else if (err.name === 'NotSupportedError') {
    // HTTPS required
  }
}

Troubleshooting

"Camera still doesn't work after npm run dev:https"

  1. Check the URL: Must be https://localhost:3000 not http://
  2. Clear permissions: Revoke and re-grant camera access
  3. Restart browser: Sometimes permissions are cached
  4. Try another browser: Chrome/Edge have best support

"Certificate error won't go away"

This is normal for self-signed certificates. You must manually bypass the warning:

  1. Click "Advanced" or "Show Details"
  2. Click "Proceed" or "Accept Risk"
  3. You only need to do this once per session

"Camera works but quality is poor"

The scanner requests high resolution:

video: {
  facingMode: 'environment',  // Back camera on mobile
  width: { ideal: 1600 },
  height: { ideal: 1200 }
}

If your camera doesn't support this resolution, it will use the highest available.

"Mobile camera shows front-facing instead of back"

Some devices don't properly support facingMode: 'environment'. You can switch cameras using the browser's camera switcher icon (usually in the address bar).

Development Workflow

Recommended workflow:

# Terminal 1: Run dev server with HTTPS
npm run dev:https

# Terminal 2: Watch for file changes (optional)
# Your editor's auto-save will trigger hot reload

# Browser: Visit https://localhost:3000/scan
# Accept certificate warning (first time only)
# Test camera scanner

For rapid iteration without camera:

# Use regular dev server
npm run dev

# Test with image uploads instead of camera
# Upload sample card images from your collection

Summary

Method Camera Access Mobile Setup
npm run dev:https βœ… Yes βœ… Yes (with IP) Accept self-signed cert
npm run dev on localhost ⚠️ Limited ❌ No Chrome/Firefox only
Upload image βœ… Works βœ… Works No setup needed
Production (HTTPS) βœ… Yes βœ… Yes Real SSL cert

For the best development experience testing the camera scanner, use npm run dev:https.

Additional Resources


Camera access is essential for the ID scanner-style card positioning guide. Following this setup ensures you can test the full scanner experience during development.

Related Posts