Emergency Hotline: Call 1-844-363-1423 (United We Dream Hotline)
ICE Encounter

The Surveillance Threat

Immigration enforcement agencies operate with massive technological budgets and are documented purchasers of:

  • Location data from commercial brokers
  • Utility records
  • Mobile phone telemetry
  • Social media data

This pipeline allows agencies to circumvent Fourth Amendment warrant requirements.

Any digital tool for immigrant communities must be engineered to prevent surveillance.


Client-Side Location Processing

Never Transmit User Location

All "find nearest" and "am I in the zone" features must execute entirely on the user's device.

Turf.js for Local Analysis

import * as turf from '@turf/turf';

// Pre-loaded zone boundary (no user data)
let borderZone;
fetch('/data/100-mile-zone.geojson')
  .then(r => r.json())
  .then(data => { borderZone = data; });

function checkLocation(lat, lng) {
  // All processing happens locally
  const userPoint = turf.point([lng, lat]);
  const isInZone = turf.booleanPointInPolygon(userPoint, borderZone);

  // Display result
  showResult(isInZone);

  // Coordinates are NEVER transmitted
  // Variable can be garbage collected immediately
}

Finding Nearest Resource

function findNearest(userLat, userLng, resources) {
  const userPoint = turf.point([userLng, userLat]);

  let nearest = null;
  let minDistance = Infinity;

  resources.features.forEach(resource => {
    const distance = turf.distance(
      userPoint,
      resource,
      { units: 'miles' }
    );

    if (distance < minDistance) {
      minDistance = distance;
      nearest = resource;
    }
  });

  // Return only the resource info, not user location
  return {
    resource: nearest.properties,
    distance: Math.round(minDistance * 10) / 10
  };
}

Zero-Tracking Architecture

No Third-Party Analytics

Never include:

Service Risk
Google Analytics IP logging, fingerprinting
Meta Pixel Cross-site tracking
Hotjar/FullStory Session recording
Commercial CDNs Request logging

Self-Hosted Analytics (If Needed)

Solution Features
Plausible Privacy-focused, no cookies
Umami Self-hosted, open source
Fathom GDPR compliant
// Plausible - no cookies, no tracking
<script defer data-domain="yoursite.org"
        src="https://plausible.yoursite.org/js/plausible.js">
</script>

IP Address Handling

# nginx.conf - anonymize IPs in logs
log_format anonymized '$remote_addr_anon - $remote_user [$time_local] '
                      '"$request" $status $body_bytes_sent';

map $remote_addr $remote_addr_anon {
    ~(?P<ip>\d+\.\d+\.\d+)\. $ip.0;
    ~(?P<ip>[^:]+:[^:]+): $ip::;
    default 0.0.0.0;
}

access_log /var/log/nginx/access.log anonymized;

Data Minimization

Never Log What You Don't Need

// Server-side request handling
app.post('/api/report', (req, res) => {
  const report = {
    // DO collect
    checkpoint_type: req.body.type,
    general_area: req.body.city, // City only, not address
    timestamp: Math.floor(Date.now() / 3600000) * 3600000, // Hour precision

    // NEVER collect
    // ip_address: req.ip,           // NO
    // user_agent: req.headers['user-agent'],  // NO
    // exact_coords: req.body.coords, // NO
  };

  saveReport(report);
});

Automated Data Purging

// Cron job to purge old data
const RETENTION_DAYS = 30;

async function purgeOldData() {
  const cutoff = Date.now() - (RETENTION_DAYS * 24 * 60 * 60 * 1000);

  await db.query(
    'DELETE FROM reports WHERE created_at < $1',
    [new Date(cutoff)]
  );

  await db.query(
    'DELETE FROM logs WHERE timestamp < $1',
    [new Date(cutoff)]
  );
}

// Run daily
setInterval(purgeOldData, 24 * 60 * 60 * 1000);

Secure Communications

HTTPS Everywhere

server {
    listen 80;
    server_name advocacy.org;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name advocacy.org;

    ssl_certificate /etc/ssl/certs/advocacy.org.pem;
    ssl_certificate_key /etc/ssl/private/advocacy.org.key;

    # Modern TLS only
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_prefer_server_ciphers on;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
}

Content Security Policy

<meta http-equiv="Content-Security-Policy" content="
  default-src 'self';
  script-src 'self' 'unsafe-inline';
  style-src 'self' 'unsafe-inline';
  img-src 'self' data: https://tile.openstreetmap.org;
  connect-src 'self' https://nominatim.openstreetmap.org;
  frame-ancestors 'none';
">

Subresource Integrity

<script src="https://unpkg.com/leaflet@1.9.4/dist/leaflet.js"
        integrity="sha384-..."
        crossorigin="anonymous"></script>

Privacy-Respecting Geocoding

Self-Hosted Nominatim

For maximum privacy, host your own geocoder:

# docker-compose.yml
services:
  nominatim:
    image: mediagis/nominatim:4.3
    volumes:
      - ./data:/nominatim/data
    environment:
      PBF_URL: https://download.geofabrik.de/north-america/us-latest.osm.pbf
    ports:
      - "8080:8080"

Proxied Requests

If using external services:

// Proxy geocoding through your server
app.get('/api/geocode', async (req, res) => {
  const { q } = req.query;

  // Don't log the query
  const result = await fetch(
    `https://nominatim.openstreetmap.org/search?q=${encodeURIComponent(q)}&format=json`
  );

  // Return without logging
  res.json(await result.json());
});

User Communication

Privacy Notice

<div class="privacy-notice">
  <h3>Your Privacy</h3>
  <p>
    This map processes your location <strong>entirely on your device</strong>.
    Your coordinates are never sent to our servers or any third party.
  </p>
  <p>
    We do not use cookies, tracking pixels, or analytics that identify you.
  </p>
</div>

Geolocation Permission Request

function requestLocation() {
  const message = `
    To find resources near you, we need your location.

    Your location stays on your device and is NEVER sent to our servers.

    Allow location access?
  `;

  if (confirm(message)) {
    navigator.geolocation.getCurrentPosition(
      handleLocation,
      handleError,
      { enableHighAccuracy: false }
    );
  }
}

Threat Modeling

Attack Vectors

Vector Mitigation
Server logs Anonymize/purge immediately
Third-party scripts Self-host all dependencies
CDN logging Use privacy-respecting CDN
Network interception HTTPS + HSTS
Browser fingerprinting Minimal JS, no cookies
Legal subpoena Don't collect data to subpoena

Data We Cannot Protect

Even with best practices, users should understand:

  • ISP can see domain accessed (not specific pages with HTTPS)
  • Device may have malware
  • Screenshots/screen recording
  • Shoulder surfing

Incident Response

If Served With Legal Process

  1. Consult legal counsel immediately
  2. Preserve (don't delete) any relevant data
  3. Review scope carefully - don't over-produce
  4. Assert applicable privileges
  5. Notify users if legally permitted

What We'd Have to Produce

With this architecture, a subpoena would yield:

Request Our Response
"User location data" "We don't collect this"
"IP addresses" "Anonymized at collection"
"User identities" "No accounts or login"
"Access logs" "Purged after 24 hours"

Related Resources