#Perplexity#Automation#Privacy#Scripts#Hacking

How to Delete All Perplexity AI History

November 28, 2025 (3 months ago)
5 min read
csmit195

/bin/scripts/purge_perplexity.js

I love Perplexity. It has effectively replaced Google for me. But my history is a graveyard of half-baked thoughts, random debugging queries, and "how to center a div" searches that I don't need to see again. So? I've created a simple bookmarklet that will delete your entire perplexity threads history. Feel free to copy the code below, or read the rest of the article to learn how it works.

The Tool

Fast, one‑click cleanup once it's set up.

  1. Log in to perplexity.ai and click Copy Bookmarklet Code.
  2. Create a new bookmark and paste the code into the URL field.
  3. Name it (for example Clear Perplexity) and click it while on perplexity.ai.

Option 2: The Source Code

For those who prefer to see everything. You get the full, unminified script that the bookmarklet runs.

  1. Open your browser's developer console (F12).
  2. Click Copy Source Code to copy the script.
  3. Paste it into the console and press Enter.
  4. Follow the on‑screen prompts.

If the bookmarklet ever stops working, you can always use Copy Source Code instead and run it directly in your browser console.

The Discovery

It turns out, the internal API is surprisingly permissive. There are no rate limits on fetching your thread lists, and the batch deletion endpoint works like a charm if you feed it the right UUIDs.

I wrote a script to automate this. I tested it on my own account and cleared 420 threads in under 10 seconds. It felt therapeutic.

Under the Hood

For the developers out there, here is how it works.

The Constants & Setup

We start by defining the environment. The API_VERSION is critical—Perplexity's backend expects this specific version string. We also set a conservative batch size of 50 threads to avoid timeouts, though I've tested it higher.

javascript
const API_VERSION = "2.18";
const BASE_URL = "https://www.perplexity.ai/rest";
const BATCH_SIZE = 50;
const BATCH_DELAY_MS = 500;

The UI Injection

Since we're running in the console context, we can't rely on React or the existing page structure. We have to inject our own UI. I created a self-contained overlay using standard DOM APIs and injected a style block to make it match the site's dark theme.

javascript
function createOverlay() {
  // ... removal of existing overlay ...
  
  overlay = document.createElement('div');
  overlay.id = 'perplexity-cleaner-overlay';
  // ... innerHTML construction for modal ...

  const style = document.createElement('style');
  style.textContent = `#perplexity-cleaner-overlay { ... }`; // CSS styles
  document.head.appendChild(style);
  document.body.appendChild(overlay);
  
  // ... grabbing references to elements ...
}

The API Client

This is the heavy lifter. We wrap fetch to include the specific headers Perplexity requires. The x-app-apiversion and x-perplexity-request-reason headers are necessary to avoid 403 Forbidden errors. We also mimic the browser's sec-ch-ua headers to look like a legitimate client.

javascript
function apiCall(url, method, body, reason) {
  return fetch(url, {
    method,
    headers: {
      "content-type": "application/json",
      "x-app-apiversion": API_VERSION, // Critical for auth
      "x-perplexity-request-endpoint": url,
      "x-perplexity-request-reason": reason,
      // ... standard browser headers ...
    },
    body: body ? JSON.stringify(body) : undefined,
    // ... credentials: "include" is vital for passing cookies ...
  }).then(r => r.ok ? r.json() : Promise.reject(new Error(`${r.status}`)));
}

The Discovery Loop

Perplexity paginates their thread list. We can't just "get all." So, we set up a loop that requests pages of 20 threads at a time, incrementing the offset until the API tells us has_next_page is false.

javascript
async function fetchAllThreads() {
  const threads = [];
  let offset = 0;
  while (true) {
    const pageThreads = await apiCall(
      `${BASE_URL}/thread/list_ask_threads?version=${API_VERSION}&source=default`,
      "POST",
      { limit: 20, ascending: false, offset, search_term: "" },
      "threads-body"
    );
    
    if (!Array.isArray(pageThreads) || pageThreads.length === 0) break;
    threads.push(...pageThreads);
    
    // Update UI with progress
    updateState('🔍', 'Scanning', `Found ${threads.length} threads...`);
    
    if (!pageThreads[pageThreads.length - 1]?.has_next_page) break;
    offset += 20;
  }
  return threads;
}

The Deletion Logic

Once we have the UUIDs, we batch them into groups of 50. This prevents the server from choking on a massive request payload. We also add a slight 500ms delay between batches to be polite to their rate limiters (if they exist).

javascript
async function deleteThreads(uuids) {
  // ... UI updates ...
  let deleted = 0;
  for (let i = 0; i < uuids.length; i += BATCH_SIZE) {
    const result = await deleteThreadBatch(uuids.slice(i, i + BATCH_SIZE));
    
    if (result.status === "success") {
      deleted += Math.min(BATCH_SIZE, uuids.length - i);
      // Update progress bar percentage
      updateState('🗑️', 'Deleting...', 
        `${deleted}/${uuids.length} threads cleared`, 
        (deleted / uuids.length) * 100
      );
    }
    
    // Polite delay
    if (i + BATCH_SIZE < uuids.length) 
      await new Promise(r => setTimeout(r, BATCH_DELAY_MS));
  }
  // ... completion state ...
}

I will be publishing more useful tools like this in the future, hope this helps someone.

Warning

This script is a blunt instrument. It does not ask "are you sure?" for individual threads. Once you confirm the total count, it deletes everything. There is no undo button, no trash can, and no recovery.

Use it wisely.

<terminate_session />

END_OF_TRANSMISSION

< READY_TO_COLLABORATE />

Currently accepting contracts for Automation Architecture, Security Research, and AI Implementations.

SYS_TIME:
MEM: 120MB

© 2026 csmit195. All systems nominal.

now on svelte-kit!