How to Scan Hundreds of Legal Files in Under an Hour

AI File Scanner Guide
✿ ✿ ✿

From Chaos to Case File

An AI-powered tool for organizing your legal evidence
No coding experience needed  ·  Free to start  ·  Built inside Google Sheets

What's inside

  • What you need before you start
  • The complete copy-paste script
  • Step-by-step setup guide
  • What the results look like
  • How to use your new inventory
You Have the Evidence. You Just Can't Find It.

If you are in the middle of a legal situation — a housing dispute, a complaint against an official, a landlord nightmare, anything involving paperwork — there is a good chance your evidence looks something like this:

  • Screenshots sitting in your phone camera roll
  • PDFs buried in your Downloads folder
  • Scanned letters saved under names like IMG_3847.jpg
  • Important emails you forwarded to yourself and never filed
You know the evidence is there. You just cannot find it, describe it, or hand it to someone else fast enough to matter.

This guide will walk you through a process that fixes all of that. By the end, you will have a clean, organized spreadsheet that lists every file, describes what is in it, pulls out dates and names, and gives each document a proper title.

The kind of thing a paralegal would charge hundreds of dollars to build. You are going to do it for almost nothing.

✿   ·   ✿   ·   ✿
What You Need Before You Start

Good news: you probably already have most of this.

A Google Account

This whole process runs inside Google Drive and Google Sheets. If you have Gmail, you already have everything. If not, go to google.com and create a free account.

Your Files in ONE Folder in Google Drive

This is the single most important thing to do before running anything. All of your legal files need to be in one Google Drive folder.

Tip: Create a folder called something like "Legal Files 2025" and drag everything into it — PDFs, screenshots, photos of documents, whatever you have. Files on your phone can be uploaded using the free Google Drive app.

You do not need to rename or sort anything yet. That is exactly what the AI is going to do for you.

An AI API Key

This is the one part that sounds technical but is actually very simple. An API key is just a password that lets the script talk to an AI service on your behalf.

Think of it like a library card. You sign up, you get a card, and the library lets you borrow things. Here, instead of books, you are borrowing the AI's ability to read and summarize your files.

When the script runs, it opens each of your files, sends it to the AI, and gets back a description. The API key is how the AI knows the request is coming from you.

Here are your main options. All three work with this guide:

  • Claude by Anthropic — anthropic.com/api
  • OpenAI (same company as ChatGPT) — platform.openai.com
  • Google Gemini (has a generous free tier) — aistudio.google.com

For each service: create an account, find the API section, and click Create API Key. Copy that key somewhere safe. You will paste it into the script in a moment.

Cost estimate: Most new accounts come with free credits. Scanning 100 files typically costs between $1 and $5. Many people can do their entire folder for free with trial credits.
Privacy note: Do not use this process for files containing Social Security numbers, bank account numbers, or passwords. For legal evidence like letters, screenshots, and scanned documents it is generally fine — but use your own judgment and review the privacy policy of whichever AI service you choose.
A Blank Google Sheet

Go to sheets.google.com and open a new blank sheet. Give it a name like "Case File Inventory." Leave it open. The script will find it automatically when it runs.

✿   ·   ✿   ·   ✿
The Script — Copy, Paste, Done

Below is the complete script. Copy everything in the code block and paste it into your Google Sheet. Step-by-step instructions on how to do that follow right after.

The script has markers right at the top with arrows pointing to exactly where your API key goes. That is the only thing you need to fill in before running it.
⋯⋯ COPY-PASTE SCRIPT: DriveFileScanner.gs ⋯⋯
Copy everything below and paste into Extensions > Apps Script
// ============================================================
// 🔑 ====== PUT YOUR API KEY RIGHT HERE 👇 ==================
const ANTHROPIC_API_KEY = "YOUR_ANTHROPIC_API_KEY_HERE";
// 🔑 ====== THAT'S THE ONLY THING YOU NEED TO CONFIGURE ====
// ============================================================

// ============================================================
// ⚙️  CONFIG — Change these if needed
// ============================================================
const DRIVE_FOLDER_ID = "YOUR_FOLDER_ID_HERE";  // 👈 Your source folder
const SHEET_NAME = "File Inventory";              // 👈 Tab name in the Sheet
const CLAUDE_MODEL = "claude-opus-4-5";           // 👈 Model to use

// MIME types to EXCLUDE (Google Docs, Sheets, Docs editors, plain text, Word)
const EXCLUDED_MIME_TYPES = [
  "application/vnd.google-apps.document",
  "application/vnd.google-apps.spreadsheet",
  "application/vnd.google-apps.presentation",
  "application/vnd.google-apps.form",
  "application/vnd.google-apps.drawing",
  "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
  "application/msword",
  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
  "application/vnd.ms-excel",
  "text/plain",
  "text/csv",
];
// ============================================================


/**
 * STEP 1: Run this first — lists all qualifying files into the sheet
 */
function listFilesFromDrive() {
  const ss = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = ss.getSheetByName(SHEET_NAME);

  if (!sheet) {
    sheet = ss.insertSheet(SHEET_NAME);
  } else {
    sheet.clearContents();
  }

  const headers = [
    "File ID",
    "File Name",
    "MIME Type",
    "File Size (bytes)",
    "Drive Link",
    "Generated Title",
    "Description",
    "Start Date",
    "End Date",
    "People Involved",
    "AI Status"
  ];
  sheet.appendRow(headers);
  sheet.getRange(1, 1, 1, headers.length).setFontWeight("bold").setBackground("#1a1a2e").setFontColor("#ffffff");
  sheet.setFrozenRows(1);

  const folder = DriveApp.getFolderById(DRIVE_FOLDER_ID);
  const files = folder.getFiles();
  let count = 0;

  while (files.hasNext()) {
    const file = files.next();
    const mimeType = file.getMimeType();
    if (EXCLUDED_MIME_TYPES.includes(mimeType)) continue;

    const row = [
      file.getId(),
      file.getName(),
      mimeType,
      file.getSize(),
      file.getUrl(),
      "",   // Generated Title
      "",   // Description
      "",   // Start Date
      "",   // End Date
      "",   // People Involved
      "PENDING"
    ];

    sheet.appendRow(row);
    count++;
  }

  sheet.autoResizeColumns(1, headers.length);
  SpreadsheetApp.getUi().alert(`✅ Done! Found ${count} qualifying files. Now run "Scan Files with AI" to get descriptions.`);
}


/**
 * STEP 2: Run this after Step 1 — calls Claude API for each PENDING row
 * Safe to re-run — only processes rows with status "PENDING"
 */
function scanFilesWithAI() {
  if (!ANTHROPIC_API_KEY || ANTHROPIC_API_KEY === "YOUR_ANTHROPIC_API_KEY_HERE") {
    SpreadsheetApp.getUi().alert("❌ Please add your Anthropic API key at the top of the script first!");
    return;
  }

  const ss = SpreadsheetApp.getActiveSpreadsheet();
  const sheet = ss.getSheetByName(SHEET_NAME);

  if (!sheet) {
    SpreadsheetApp.getUi().alert("❌ No sheet found. Run 'List Files from Drive' first.");
    return;
  }

  const data = sheet.getDataRange().getValues();
  let processedCount = 0;
  let errorCount = 0;

  for (let i = 1; i < data.length; i++) {
    const row = data[i];
    const status = row[10];
    if (status !== "PENDING") continue;

    const fileId   = row[0];
    const fileName = row[1];
    const mimeType = row[2];
    const sheetRow = i + 1;

    try {
      Logger.log(`Processing row ${sheetRow}: ${fileName}`);
      sheet.getRange(sheetRow, 11).setValue("PROCESSING...");
      SpreadsheetApp.flush();

      const aiResult = callClaudeForFile(fileId, fileName, mimeType);

      sheet.getRange(sheetRow, 6).setValue(aiResult.title);
      sheet.getRange(sheetRow, 7).setValue(aiResult.description);
      sheet.getRange(sheetRow, 8).setValue(aiResult.startDate);
      sheet.getRange(sheetRow, 9).setValue(aiResult.endDate);
      sheet.getRange(sheetRow, 10).setValue(aiResult.people);
      sheet.getRange(sheetRow, 11).setValue("✅ DONE");

      processedCount++;
      Utilities.sleep(1000);

    } catch (e) {
      Logger.log(`Error on row ${sheetRow}: ${e.message}`);
      sheet.getRange(sheetRow, 11).setValue("❌ ERROR: " + e.message.substring(0, 80));
      errorCount++;
    }

    SpreadsheetApp.flush();
  }

  SpreadsheetApp.getUi().alert(`✅ AI scan complete!\nProcessed: ${processedCount}\nErrors: ${errorCount}`);
}


/**
 * Fetches a file from Drive and sends it to Claude for analysis.
 * Returns an object: { title, description, startDate, endDate, people }
 */
function callClaudeForFile(fileId, fileName, mimeType) {
  const file = DriveApp.getFileById(fileId);
  const blob = file.getBlob();
  const base64Data = Utilities.base64Encode(blob.getBytes());

  let contentArray = [];
  const isPdf = mimeType === "application/pdf";
  const isImage = mimeType.startsWith("image/");

  const systemPrompt = `You are a document analyst. The user will give you a file. Analyze it and respond ONLY with valid JSON — no markdown, no explanation, just raw JSON.

Return this exact structure:
{
  "title": "YYYY-MM-DD Descriptive Title Including Key Parties",
  "description": "2-3 sentence summary of what this document is about",
  "startDate": "YYYY-MM-DD or 'Unknown'",
  "endDate": "YYYY-MM-DD or 'Unknown'",
  "people": "Comma-separated list of names mentioned, or 'None identified'"
}

Rules:
- Title format MUST start with the date like: "2025-08-14 Notice to Vacate — Landlord to Tenant"
- If only one date, use the same date for both startDate and endDate
- For dates: look inside the document content only. IGNORE any date embedded in a screenshot filename (e.g., "Screenshot 2025-01-01" is NOT the document date)
- If no date can be determined from the content itself, use "Unknown" for both date fields
- Keep description factual and concise`;

  if (isPdf) {
    contentArray = [
      { type: "document", source: { type: "base64", media_type: "application/pdf", data: base64Data } },
      { type: "text", text: `Analyze this file. Its filename is: "${fileName}"` }
    ];
  } else if (isImage) {
    contentArray = [
      { type: "image", source: { type: "base64", media_type: mimeType, data: base64Data } },
      { type: "text", text: `Analyze this file. Its filename is: "${fileName}"` }
    ];
  } else {
    contentArray = [
      { type: "text", text: `I have a file named "${fileName}" with MIME type "${mimeType}". I cannot extract its content directly, but please generate a best-guess title and description based on the filename alone. Follow the JSON structure exactly.` }
    ];
  }

  const payload = {
    model: CLAUDE_MODEL,
    max_tokens: 500,
    system: systemPrompt,
    messages: [{ role: "user", content: contentArray }]
  };

  const options = {
    method: "post",
    contentType: "application/json",
    headers: {
      "x-api-key": ANTHROPIC_API_KEY,
      "anthropic-version": "2023-06-01",
      "anthropic-beta": "pdfs-2024-09-25"
    },
    payload: JSON.stringify(payload),
    muteHttpExceptions: true
  };

  const response = UrlFetchApp.fetch("https://api.anthropic.com/v1/messages", options);
  const responseCode = response.getResponseCode();
  const responseText = response.getContentText();

  if (responseCode !== 200) {
    throw new Error(`API returned ${responseCode}: ${responseText.substring(0, 200)}`);
  }

  const parsed = JSON.parse(responseText);
  const rawText = parsed.content[0].text.trim();
  const cleanJson = rawText.replace(/^```json\s*/i, "").replace(/^```\s*/i, "").replace(/```\s*$/i, "").trim();
  const result = JSON.parse(cleanJson);

  return {
    title:       result.title       || "Unknown",
    description: result.description || "No description returned",
    startDate:   result.startDate   || "Unknown",
    endDate:     result.endDate     || "Unknown",
    people:      result.people      || "None identified"
  };
}


/**
 * Adds a custom menu to the spreadsheet when opened
 */
function onOpen() {
  SpreadsheetApp.getUi()
    .createMenu("📁 Drive Scanner")
    .addItem("Step 1 — List Files from Drive", "listFilesFromDrive")
    .addSeparator()
    .addItem("Step 2 — Scan Files with AI", "scanFilesWithAI")
    .addToUi();
}
✿   ·   ✿   ·   ✿
How to Set It Up (Step by Step)
Open the Script Editor
  1. In your Google Sheet, click Extensions in the top menu bar
  2. Click Apps Script — a new tab opens
  3. Delete everything you see in that tab (there will be a placeholder function already there)
  4. Paste the entire script from above into that empty space
  5. Press Ctrl+S on Windows or Cmd+S on Mac to save
Add Your API Key and Folder ID

Near the very top of the script you just pasted, you will see two things clearly marked with arrows:

  • A line for your API key
  • A line for your Google Drive folder ID

To find your folder ID: open your Drive folder in a browser. Look at the URL. The long string of letters and numbers at the very end (after the last slash) is your folder ID. Copy and paste that in.

Example: If your URL is drive.google.com/drive/folders/1ABC123xyz then your folder ID is 1ABC123xyz
Authorize the Script
  1. Click the Run button (the triangle play button) in Apps Script
  2. Google will ask you to authorize. Click Review Permissions
  3. Choose your Google account
  4. You may see a warning saying "Google has not verified this app" — that is normal for personal scripts
  5. Click Advanced, then click "Go to your script name" at the bottom
  6. Click Allow

This only happens once. It is just Google confirming you want the script to access your Drive and Sheet.

✿   ·   ✿   ·   ✿
Running the Scanner

Go back to your Google Sheet and refresh the page. You should now see a new menu item in the top bar called Drive Scanner. Click it.

Step 1 — List Your Files

Click Step 1 — List Files from Drive. The script scans your folder and fills in one row per qualifying file. It automatically skips Google Docs, Word documents, spreadsheets, and plain text files. PDFs, images, and most other file types are included.

Good to know: A pop-up will tell you how many files were found when it finishes. This usually takes under a minute even for large folders.
Step 2 — Scan with AI

Click Step 2 — Scan Files with AI. This is where it all happens. The script goes row by row, opens each file, sends it to the AI, and waits for a response.

Depending on how many files you have, this step could take anywhere from a few minutes to half an hour. You do not need to watch it — leave the tab open and come back. If anything interrupts it, just run Step 2 again and it will pick up exactly where it left off.
✿   ·   ✿   ·   ✿
What Your Spreadsheet Will Look Like

When the scan is done, every row in your sheet will have all of this filled in:

  • Generated Title — starts with the date, like "2025-08-14 Notice to Vacate from Landlord"
  • Description — 2 to 3 plain-English sentences about what the document says or shows
  • Start Date and End Date — pulled from the document content, not the filename
  • People Involved — any names the AI spotted in the document
  • Status — whether the scan succeeded or had an error

Here is an example of what a few rows might look like after the scan completes:

✿ Example output — your actual results will reflect your own documents

⚠️ All names, dates, and details in this table are completely fictional and used for illustration purposes only.

Generated Title Description Start Date People Involved Status
2025-03-02 Notice to Vacate — Property Manager to Tenant A formal written notice issued by the property manager demanding the tenant vacate the premises within 30 days. The notice cites lease violations including unauthorized subletting. Signed by the property manager and addressed to the tenant of record. 2025-03-02 R. Holloway (manager), D. Chen (tenant) ✅ DONE
2025-03-18 Police Incident Report — Trespassing Complaint An official incident report filed with local police documenting a trespassing complaint. The reporting officer notes that the suspect was observed on the property after a no-contact order had been issued. Report includes badge numbers and case reference. 2025-03-18 Officer T. Reyes, J. Morales (complainant) ✅ DONE
2025-04-10 Text Message Screenshots — Harassment Documentation A series of screenshots showing text messages sent between April 8 and April 10, 2025. The messages contain repeated unwanted contact and threatening language from the sender. Screenshots include timestamps and phone numbers. 2025-04-08 None identified (numbers only) ✅ DONE
Unknown — Handwritten Letter re: Rent Dispute A handwritten letter disputing a claimed rent overpayment from the prior year. The author references a specific payment made in cash and requests a receipt or correction to the ledger. No date is written on the letter itself. Unknown Author name illegible ✅ DONE
A well-organized file inventory is not just a convenience. It is a tool that lets you walk into any meeting, phone call, or legal appointment and immediately answer: what do I have, and when did it happen?
✿   ·   ✿   ·   ✿
What to Do With It Now
Build Your Timeline

Sort the sheet by Start Date. You now have a chronological view of your entire case. Gaps in the timeline are just as important as the documents — they show you what might be missing.

Find Your Strongest Evidence

Scroll through the descriptions. Look for documents with specific dates, named parties, and concrete actions or statements. Those are the ones an attorney or advocate will want to see first.

Share It

You can share the Google Sheet directly with anyone — an attorney, an advocate, a family member helping you. You can also download it as a PDF or Excel file. Handing someone a clean, organized inventory shows that you are serious and that you know what you have.

Keep It Updated

Every time a new file comes in, drop it in your Drive folder and run Step 2 again. The script skips everything already scanned and only processes new additions.

✿   ·   ✿   ·   ✿
Common Questions
What if the AI gets a date wrong?

It happens sometimes. Just correct it manually in the sheet. The AI's output is a starting point, not a final answer.

What if some files show an error?

Some unusual file types cannot be sent to the AI. The Status column will say ERROR for those rows. You can review them manually or skip them.

Is this safe to use for sensitive documents?

Your files are sent to whichever AI service you chose. Those companies have privacy policies that govern how they handle your data. API usage is generally not used to train their models, but always check the current policy. Avoid scanning documents with Social Security numbers, bank account numbers, or passwords.

Do I need any coding experience?

No. You are copying and pasting. The hardest part is finding your folder ID in the Drive URL, and even that takes about ten seconds.

✿   ·   ✿   ·   ✿
You Collected Those Files for a Reason

Every screenshot, every scanned letter, every PDF you saved — you kept them because they mattered. This process makes sure they actually get used.

In an hour or less, you go from a chaotic folder of nameless files to a clean, searchable, shareable inventory of your entire case.


You deserve tools that work as hard as you do. This is one of them.
✿   ✿   ✿
Previous
Previous

When the System Becomes the Weapon

Next
Next

Before You Take It to Court: Reporting Police Misconduct in Utah