recv0Source

Press record once. Test forever.

No tape0.00 s

Step 1: Open your app’s console

Open the app whose streaming you want to test, then open DevTools and its Console: ⌥⌘J on Mac, Ctrl+Shift+J on Windows and Linux.

Chrome may refuse the first paste. If it asks, type allow pasting and press Enter.

Step 2: Paste the recorder and press Enter

(() => {
  const say = (msg) => console.log('%c● rec%c ' + msg, 'color:#ff3b5c;font-weight:bold', '');
  if (window.rec) return say('already recording. Trigger a streamed response, then run rec.copy()');
  const devtoolsCopy = typeof copy === 'function' ? copy : null;
  const tapes = [];
  const realFetch = window.fetch;
  window.rec = {
    tapes,
    get last() { return tapes[tapes.length - 1]; },
    copy() {
      const last = tapes[tapes.length - 1];
      if (!last) return say('nothing captured yet. Trigger a streamed response first.');
      const json = JSON.stringify(last);
      try {
        if (devtoolsCopy) { devtoolsCopy(json); return say('copied ' + last.chunks.length + ' chunks. Paste them into rec.'); }
      } catch (e) {}
      console.log(json);
      say('right-click the line above, choose "Copy string contents", and paste it into rec.');
    },
  };
  window.fetch = async function (input, init) {
    const t0 = performance.now();
    const res = await realFetch.call(this, input, init);
    const url = typeof input === 'string' ? input : (input && input.url) || String(input);
    const type = res.headers.get('content-type') || '';
    if (!res.body || !(type.includes('event-stream') || /chat\/completions/.test(url))) return res;
    const [mine, theirs] = res.body.tee();
    const capture = { provider: 'openai', t0, chunks: [] };
    (async () => {
      const reader = mine.pipeThrough(new TextDecoderStream()).getReader();
      for (;;) {
        const { done, value } = await reader.read();
        if (done) break;
        capture.chunks.push({ t: performance.now(), raw: value });
      }
      tapes.push(capture);
      say('captured ' + capture.chunks.length + ' chunks. Now run: rec.copy()');
    })().catch((e) => say('capture failed: ' + e));
    return new Response(theirs, { status: res.status, statusText: res.statusText, headers: res.headers });
  };
  say('recording. Now send a message in your app and let the answer stream in.');
})();

The console should say ● rec recording. It records response chunks only, never headers, prompts or keys.

Step 3: Stream one answer

In your app, send a message and let the whole answer stream in. When it finishes, the console says ● rec captured N chunks.

Step 4: Copy the capture

Type rec.copy() in the console and press Enter. The capture is now on your clipboard.

Step 5: Paste it here

Anyone with a tape’s URL can read its text. Don’t record sensitive answers.