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

Community-Powered Intelligence

Community defense networks rely on crowdsourcing to identify:

  • Sudden workplace raids
  • Temporary "roving" checkpoints
  • ICE vehicle sightings
  • Enforcement activity patterns

Aggregating, verifying, and acting on this data involves significant technical and ethical complexity.


Report Collection Architecture

Data Points to Collect

Field Purpose Privacy Note
Type Checkpoint, raid, vehicle Required
General area City/neighborhood Not exact address
Time Hour precision Not exact minute
Description Activity observed Free text
Duration Still active? Time decay

Data NOT to Collect

Field Risk
❌ Reporter identity Retaliation
❌ Exact GPS coords Location tracking
❌ IP address Identification
❌ Device fingerprint Tracking
❌ Photos of individuals Privacy/safety

Anonymous Submission

Frontend Form

<form id="report-form" action="/api/report" method="POST">
  <select name="type" required>
    <option value="">Select type...</option>
    <option value="checkpoint">Checkpoint</option>
    <option value="raid">Raid/Operation</option>
    <option value="vehicle">ICE Vehicle</option>
    <option value="patrol">Roving Patrol</option>
  </select>

  <input type="text" name="area"
         placeholder="City or neighborhood"
         required>

  <select name="highway" id="highway-select">
    <option value="">Highway (if applicable)</option>
    <option value="I-8">I-8</option>
    <option value="I-10">I-10</option>
    <!-- etc -->
  </select>

  <textarea name="description"
            placeholder="What did you observe?"></textarea>

  <label>
    <input type="checkbox" name="still_active">
    Still active when reporting
  </label>

  <button type="submit">Submit Report</button>
</form>

Backend Processing

app.post('/api/report', async (req, res) => {
  const report = {
    id: generateUUID(),
    type: sanitize(req.body.type),
    area: sanitize(req.body.area),
    highway: sanitize(req.body.highway),
    description: sanitize(req.body.description),
    still_active: req.body.still_active === 'on',

    // Coarse timestamp (hour precision)
    timestamp: Math.floor(Date.now() / 3600000) * 3600000,

    // Initial status
    status: 'unverified',
    confidence: 0.3
  };

  // DO NOT LOG: req.ip, req.headers

  await saveReport(report);

  // Trigger verification workflow
  await queueForVerification(report);

  res.json({ success: true, id: report.id });
});

Verification Workflows

Multi-Source Corroboration

async function verifyReport(report) {
  const nearbyReports = await findReportsNear(
    report.area,
    { radius: 5, timeWindow: '2h' }
  );

  // Bayesian confidence update
  let confidence = report.confidence;

  nearbyReports.forEach(other => {
    if (other.id !== report.id) {
      // Corroborating reports increase confidence
      const similarity = calculateSimilarity(report, other);
      confidence = bayesianUpdate(confidence, similarity);
    }
  });

  // Check against known patterns
  const historicalMatch = await matchHistoricalPattern(report);
  if (historicalMatch) {
    confidence = bayesianUpdate(confidence, 0.8);
  }

  return confidence;
}

Confidence Levels

Level Confidence Display
Unverified < 0.3 Gray, small
Possible 0.3 - 0.6 Yellow, medium
Likely 0.6 - 0.8 Orange, full size
Confirmed > 0.8 Red, prominent

Human Review Queue

// Flag reports for human review
if (confidence < 0.3 && description.length > 200) {
  await flagForReview(report, 'Long description, low confidence');
}

if (isAnomaly(report)) {
  await flagForReview(report, 'Anomalous location/time');
}

Time Decay

The Problem

Enforcement actions are highly temporal. A checkpoint reported 3 hours ago may no longer exist.

Visual Decay Implementation

function getReportStyle(report) {
  const ageHours = (Date.now() - report.timestamp) / (1000 * 60 * 60);

  // Reports fade over time
  const opacity = Math.max(0.2, 1 - (ageHours / 24));
  const scale = Math.max(0.5, 1 - (ageHours / 48));

  return {
    opacity,
    scale,
    label: getAgeLabel(ageHours)
  };
}

function getAgeLabel(hours) {
  if (hours < 1) return 'Just reported';
  if (hours < 2) return '1-2 hours ago';
  if (hours < 6) return 'Few hours ago';
  if (hours < 24) return 'Earlier today';
  return 'Yesterday or older';
}

CSS Animation

.report-marker {
  transition: opacity 0.3s, transform 0.3s;
}

.report-marker.fading {
  animation: pulse 2s infinite;
}

@keyframes pulse {
  0%, 100% { opacity: 0.6; }
  50% { opacity: 1; }
}

Spam and Abuse Prevention

Rate Limiting

const rateLimit = require('express-rate-limit');

const reportLimiter = rateLimit({
  windowMs: 15 * 60 * 1000, // 15 minutes
  max: 5, // 5 reports per window
  message: 'Too many reports. Please try again later.',
  // Don't log IPs
  keyGenerator: (req) => hashIP(req.ip)
});

app.post('/api/report', reportLimiter, handleReport);

Anomaly Detection

function isAnomaly(report) {
  // Check if location has any enforcement history
  const historicalActivity = await getHistoricalActivity(report.area);
  if (historicalActivity.count === 0) {
    return true; // Unusual location
  }

  // Check if time is unusual for this location
  const typicalTimes = historicalActivity.typicalHours;
  const reportHour = new Date(report.timestamp).getHours();
  if (!typicalTimes.includes(reportHour)) {
    return true; // Unusual time
  }

  return false;
}

Content Moderation

const BLOCKED_PATTERNS = [
  /personal\s+information/i,
  /license\s+plate/i,
  /name\s+of/i,
  /photo\s+of\s+person/i
];

function moderateContent(description) {
  for (const pattern of BLOCKED_PATTERNS) {
    if (pattern.test(description)) {
      return {
        allowed: false,
        reason: 'Content may contain personal information'
      };
    }
  }
  return { allowed: true };
}

Legal Framework

What You CAN Report

  • Public observation of enforcement activity
  • Checkpoint locations on public roads
  • General descriptions of activity
  • Time and general area

What You CANNOT Include

Content Risk
Photos of individuals Privacy violation
Names of officers Potential harassment
License plates Privacy violation
Tactics to evade Potentially illegal
Instructions to interfere Federal charges

Terms of Service

## User Agreement

By submitting a report, you agree:

1. Your report is based on personal observation
2. You will not include personal identifying information
3. You will not provide instructions for evading enforcement
4. You understand reports are for informational purposes only
5. [Organization] is not liable for report accuracy

Rapid Response Integration

Alert Triggers

async function processVerifiedReport(report) {
  if (report.confidence > 0.7 && report.still_active) {
    // Trigger rapid response notification
    await notifyRapidResponse({
      type: report.type,
      area: report.area,
      description: report.description,
      link: `https://map.org/reports/${report.id}`
    });
  }
}

Notification Channels

async function notifyRapidResponse(alert) {
  // Signal group
  await signalBot.send(RAPID_RESPONSE_GROUP, formatAlert(alert));

  // Telegram channel
  await telegramBot.send(ALERT_CHANNEL, formatAlert(alert));

  // SMS (if critical)
  if (alert.type === 'raid') {
    await smsService.broadcast(COORDINATORS, formatSMS(alert));
  }
}

Existing Platforms

Ushahidi

Battle-tested crisis mapping platform:

  • Anonymous submission
  • Verification workflows
  • Map visualization
  • API access

Recommended for organizations without dev resources.

Custom Implementation

For specific needs:

Approach Effort Flexibility
Ushahidi Low Medium
Modified OSM Medium Medium
Custom build High Full

Data Retention

Aggressive Purging

// Daily cleanup job
async function cleanupOldReports() {
  const cutoffs = {
    unverified: 24 * 60 * 60 * 1000,  // 24 hours
    verified: 7 * 24 * 60 * 60 * 1000, // 7 days
    archived: 30 * 24 * 60 * 60 * 1000 // 30 days
  };

  for (const [status, maxAge] of Object.entries(cutoffs)) {
    const cutoff = Date.now() - maxAge;
    await db.query(
      'DELETE FROM reports WHERE status = $1 AND timestamp < $2',
      [status, new Date(cutoff)]
    );
  }
}

What to Preserve

For historical analysis, retain only:

  • Aggregated statistics
  • Geographic patterns
  • Time trends
  • No individual reports after 30 days

Related Resources