# Where does Jitsi save transcripts and how do I download them?

> Jigasi saves complete transcripts when its transcription session ends, if a file publisher is enabled. Stock Docker stable-11146 through stable-11248 stores them under ${CONFIG}/storage/transcripts, while package defaults use /var/lib/jigasi/transcripts. Docker's /transcripts route serves known file URLs without a meeting permission check, so block it or add authenticated delivery. The bridge proxy can capture final messages as JSONL dumps, with separate storage and retention. [S1][S2][S3][S4][S9]

Source: https://jitsi.help/guides/jitsi-transcripts-save-download/
Updated: October 6, 2026
Publisher: Jitsi Help (https://jitsi.help/)

## Who this is for

Use this after captions work and you need a retained file or controlled delivery. Follow the existing [Vosk setup](/guides/jitsi-transcription-vosk/) or [bridge guide](/guides/jitsi-bridge-transcription-opus-proxy/) for recognition. Client caption options and server file saving have separate controls. [S3][S9][S11][S12]

## How it works

Jigasi's `SAVE_TXT` and `SAVE_JSON` enable complete file publishers. `SEND_JSON` sends live results for captions; `SEND_TXT` sends recognized speech into meeting chat. Neither emails a completed file. `BASE_URL` constructs advertised links; it does not create a web server. [S3]

Saved names follow `DIRECTORY/<UTC-Instant>_<UUID>/transcript_<UTC-Instant>_<UUID>.txt`, or `.json`. Directory and filename identifiers differ. Each format has its own publisher and generated directory, so both formats need not share one folder. Files appear when the transcription session ends. [S3]

TXT contains meeting details, participant names, UTC speech timestamps and meeting events. JSON retains structured events, alternatives and metadata, which can include email or identity fields. Both use UTF-8 and retain final speech results, not interim revisions. [S3]

| Installation | Host folder | Inside transcriber |
|---|---|---|
| Stock Docker stable-11031, before rootless | `${CONFIG}/transcripts` | `/tmp/transcripts` |
| Stock Docker stable-11146 through stable-11248 | `${CONFIG}/storage/transcripts` | `/tmp/transcripts` |
| Released Debian/Ubuntu Jigasi | `/var/lib/jigasi/transcripts` | Same host path |

The Docker move shipped with rootless PR #2258 in stable-11146. Web mounts the current folder read-only at `/usr/share/jitsi-meet/transcripts`. Existing custom `DIRECTORY=/config/transcripts` configurations use their own path; check their mounts instead of assuming this table applies. [S1][S2][S3]

## Before you start

Checked October 6, 2026: Docker's latest release remains `stable-11248`. Package steps cover Jigasi `1.1-415-g2750d54-1`. Keep Compose files and images from one release, preserve recognition/XMPP settings, and schedule recreation without active meetings. [S1][S6][S10]

Obtain participant agreement for retention and delivery. Choose who can retrieve files and when copies expire. For S3, prepare a private bucket and credentials restricted to the archive prefix. No real credentials belong in this guide or your repository. [S3][S8]

## Steps

1. **Docker stable-11248: protect downloads first.** Set `CONFIG` to your actual `.env` value. These commands use its handbook default. Keep existing backend overlays in the helper. [S1][S4][S10]

   ```sh
   CONFIG="$HOME/.jitsi-meet-cfg"
   mkdir -p "${CONFIG}/storage/transcripts" "${CONFIG}/web/nginx-custom"
   sudo chown 1000:1000 "${CONFIG}/storage/transcripts"
   sudo chmod 750 "${CONFIG}/storage/transcripts"
   dc() {
       docker compose -f docker-compose.yml -f transcriber.yml "$@"
   }
   ```

   Save this as `${CONFIG}/web/nginx-custom/transcripts-private.conf`, a filename chosen here. Startup copies it into the included runtime directory. These rules override the stock static-file regex: [S4][S10]

   ```nginx
   location = /transcripts { return 403; }
   location ^~ /transcripts/ { return 403; }
   ```

   Run `dc up -d --force-recreate web`, then `dc exec -T web nginx -t -c /run/web/config/nginx/nginx.conf`. This blocks participant download links too. Deliver through your authenticated application with meeting-specific authorization, or an administrator, rather than removing protection. [S4][S10]

2. **Docker stable-11248: enable files.** In `.env`, set `JIGASI_TRANSCRIBER_ENABLE_SAVING=1` and `JIGASI_TRANSCRIBER_ADVERTISE_URL=false`. Append these assignments to `${CONFIG}/transcriber/custom-sip-communicator.properties`, preserving existing entries and avoiding conflicting duplicates: [S1][S5]

   ```properties
   org.jitsi.jigasi.transcription.DIRECTORY=/tmp/transcripts
   org.jitsi.jigasi.transcription.SAVE_TXT=true
   org.jitsi.jigasi.transcription.SAVE_JSON=true
   org.jitsi.jigasi.transcription.SEND_JSON=true
   org.jitsi.jigasi.transcription.SEND_TXT=false
   ```

   Make the custom file readable by UID 1000. Run `dc config --quiet` and `dc up -d --force-recreate transcriber`. At session end, administrators can retrieve generated files directly from host storage. Without protection, the URL is `${PUBLIC_URL}/transcripts/<generated-directory>/<generated-filename>`; hiding its advertisement is not access control. [S1][S3][S4][S5][S10]

3. **Docker stable-11248: optional S3 hook.** PR #2225 closed without merging on June 7, 2026. Its proposed hook environment variables are unavailable in this release. Use custom properties and an executable script instead. The hook receives one absolute transcript-directory argument, once per publisher; Jigasi does not wait, retry or check its exit status. [S5][S7]

   Run `mkdir -p "${CONFIG}/transcript-hooks"`, then save this example as `${CONFIG}/transcript-hooks/upload-s3.sh`. Replace `amzn-s3-demo-bucket` with your private bucket. It uploads only TXT/JSON, records its own result and retains local files. [S7][S8][S10]

   ```sh
   #!/bin/sh
   set -eu
   umask 077
   dir=${1:?Missing transcript directory}
   exec >>"$dir/s3-upload.log" 2>&1
   found=false
   for file in "$dir"/*.txt "$dir"/*.json; do
       [ -f "$file" ] || continue
       found=true
       if aws s3 cp "$file" "s3://amzn-s3-demo-bucket/jigasi/$(basename "$dir")/" --only-show-errors; then
           :
       else
           printf '%s\n' 'S3 upload failed'
           exit 1
       fi
   done
   [ "$found" = true ] || { printf '%s\n' 'No saved transcript found'; exit 1; }
   printf '%s\n' 'S3 upload completed'
   ```

   Run `chmod 755 "${CONFIG}/transcript-hooks" "${CONFIG}/transcript-hooks/upload-s3.sh"`. Stock Jigasi lacks AWS CLI. Save this example as `Dockerfile.transcript-s3`: [S5][S8][S10]

   ```dockerfile
   FROM ghcr.io/jitsi/jigasi:stable-11248
   USER root
   RUN apt-dpkg-wrap apt-get update \
       && apt-dpkg-wrap apt-get install -y --no-install-recommends awscli \
       && apt-cleanup
   USER s6
   ```

   Build with `docker build -f Dockerfile.transcript-s3 -t jigasi-transcript-s3:stable-11248 .`. Provision an existing protected shared-credentials file at `${CONFIG}/transcript-aws/credentials`, outside Git, readable by UID 1000 with mode 600. Save this as `transcript-s3.yml`; set your bucket region: [S5][S8][S10]

   ```yaml
   services:
     transcriber:
       image: jigasi-transcript-s3:stable-11248
       environment:
         AWS_SHARED_CREDENTIALS_FILE: /opt/transcript-aws/credentials
         AWS_DEFAULT_REGION: us-east-1
       volumes:
         - ${CONFIG}/transcript-hooks:/opt/transcript-hooks:ro
         - ${CONFIG}/transcript-aws/credentials:/opt/transcript-aws/credentials:ro
   ```

   Append to the same custom properties file: [S7]

   ```properties
   org.jitsi.jigasi.transcription.EXECUTE_SCRIPTS=true
   org.jitsi.jigasi.transcription.SCRIPTS_TO_EXECUTE_LIST=/opt/transcript-hooks/upload-s3.sh
   org.jitsi.jigasi.transcription.SCRIPTS_TO_EXECUTE_LIST_SEPARATOR=,
   ```

   Add `-f transcript-s3.yml` to `dc`, validate, then recreate `transcriber`. An IAM role is another credential route; containers need working metadata access if relying on an instance role. Never bake keys into the image. [S8][S10]

4. **Debian/Ubuntu Jigasi baseline: enable storage and the same hook.** [S3][S6][S10]

   ```sh
   sudo install -d -o jigasi -g jitsi -m 750 /var/lib/jigasi/transcripts
   ```

   Edit `/etc/jitsi/jigasi/sip-communicator.properties`: use step 2's flags, with `org.jitsi.jigasi.transcription.DIRECTORY=/var/lib/jigasi/transcripts` and `org.jitsi.jigasi.transcription.ADVERTISE_URL=false`. Packages do not create Docker's download route. [S3][S6]

   For uploads, use the [official system installer](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html): [S8][S10]

   ```sh
   curl -fsSL https://awscli.amazonaws.com/v2/install.sh | sudo bash -s -- --system
   ```

   Save the same script locally as `upload-s3.sh`, then run `sudo install -m 755 upload-s3.sh /usr/local/bin/jitsi-transcript-upload-s3`. Configure credentials for service user `jigasi`, not just your SSH login. Use step 3's hook properties with that absolute script path. Run `sudo systemctl restart jigasi` during maintenance. [S6][S7][S8][S10]

5. **Bridge proxy `6747f187`: capture separately.** Add to your existing `opus-transcriber-proxy` service, retaining the [bridge guide's](/guides/jitsi-bridge-transcription-opus-proxy/) session-ID configuration: [S9][S11]

   ```yaml
   environment:
     DUMP_TRANSCRIPTS: "true"
     DUMP_BASE_PATH: /data
   volumes:
     - ${CONFIG}/storage/bridge-transcripts:/data:Z
   ```

   Run `mkdir -p "${CONFIG}/storage/bridge-transcripts"` and make it writable by the proxy's actual runtime user. Its image does not declare Jitsi's UID 1000. Recreate the proxy. Final messages become `/data/<sessionId>/transcript.jsonl`, one JSON object per line with capture timestamp and full message. This documented debug capture has no automatic cleanup or Jigasi download-link delivery. Keep it outside web-served storage. [S9][S10]

6. **Both paths: retain and delete deliberately.** Example Docker candidates older than 30 days: [S10]

   ```sh
   find "${CONFIG}/storage/transcripts" -type f -mtime +30 -print
   ```

   Check upload success and your policy before replacing `-print` with `-delete`. Use the corresponding package/bridge directory separately. Configure S3 lifecycle expiration too, including noncurrent versions where versioning is enabled. Deleting local files does not remove S3 objects, backups or cached downloads. [S8][S10]

## Configuration reference

Jigasi rows below use the exact prefix `org.jitsi.jigasi.transcription.` in properties files. Docker appends custom properties after its generated settings. [S3][S5][S7]

| Setting | Default: released code / stock Docker | Purpose |
|---|---|---|
| `DIRECTORY` | `/var/lib/jigasi/transcripts` / `/tmp/transcripts` | Saved files. [S3][S1] |
| `BASE_URL` | `http://localhost/` / `${PUBLIC_URL}/transcripts` | Advertised URL base. [S3][S1] |
| `SAVE_TXT`, `SAVE_JSON` | `false`, `false` / `true`, `false` | Complete file formats. [S3][S1] |
| `SEND_TXT`, `SEND_JSON` | `false`, `true` / same | Live chat/captions. [S3][S1] |
| `ADVERTISE_URL` | `false` / `false` | Announce saved-file links. [S3][S1] |
| `EXECUTE_SCRIPTS` | `false` / no mapping | Enable hook. [S7] |
| `SCRIPTS_TO_EXECUTE_LIST` | `script/example_handle_transcript_directory.sh` / no mapping | Executable paths; explicitly override. [S7] |
| `SCRIPTS_TO_EXECUTE_LIST_SEPARATOR` | `,` / no mapping | Java regex delimiter; avoid spaces around list entries. [S7] |
| `JIGASI_TRANSCRIBER_ENABLE_SAVING` | Docker `.env`: `1` | Emit saving block. [S1] |
| `JIGASI_TRANSCRIBER_ADVERTISE_URL`, `JIGASI_TRANSCRIBER_SEND_TXT` | Docker `.env`: `false`, `false` | Map corresponding properties. [S1] |
| `CONFIG`, `PUBLIC_URL` | Docker `.env`: `~/.jitsi-meet-cfg`, setup-specific | Storage root and external URL. [S1] |
| `location`, `return` | Web custom Nginx config: no block by default | Example disables transcript downloads. [S4][S10] |
| `AWS_SHARED_CREDENTIALS_FILE`, `AWS_DEFAULT_REGION` | AWS CLI environment: `~/.aws/credentials`, unset region | Example selects private credentials and bucket region. [S8] |
| `DUMP_TRANSCRIPTS`, `DUMP_BASE_PATH` | Proxy environment: `false`, `/tmp` | Optional JSONL capture. [S9] |

## Common mistakes

Jigasi's README says TXT saving defaults on, but released code defaults off. Docker explicitly enables TXT. A custom directory from an older setup can override the new storage mapping. Changing generated `/run/jigasi/config/sip-communicator.properties` disappears on recreation. [S1][S3][S5][S12]

`JIGASI_TRANSCRIBER_ENABLE_SAVING=0` omits Docker's saving block, allowing code defaults to disable files unless custom flags enable them again. For explicit disablement, set both saving properties false. Startup still checks `/tmp/transcripts` write access. [S1][S3][S5]

## Verify

Finish a test transcription session after speaking a unique sentence. Run `dc logs --tail=100 transcriber` and: [S3][S10]

```sh
find "${CONFIG}/storage/transcripts" -type f \( -name '*.txt' -o -name '*.json' \) -print
TRANSCRIPT_FILE=$(find "${CONFIG}/storage/transcripts" -type f -name '*.txt' -print -quit)
TRANSCRIPT_PATH=${TRANSCRIPT_FILE#"${CONFIG}/storage/transcripts/"}
[ -n "$TRANSCRIPT_FILE" ] && curl -sS -o /dev/null -w '%{http_code}\n' \
    "https://meet.example.com/transcripts/${TRANSCRIPT_PATH}"
```

Expect the exact log prefix `Wrote final transcript to ` followed by the generated path. Open the actual file and confirm your sentence. The known-file HTTP check must print `403`; test every public entry point, including the origin if using a CDN. For S3, require your hook's `S3 upload completed` log and verify the actual object with `aws s3 ls s3://amzn-s3-demo-bucket/jigasi/ --recursive`, using your bucket. [S3][S8][S10]

For bridge dumps, check the log prefix `Transcript dump enabled: ` and inspect the generated JSONL with `jq -r '.message.transcript[].text' transcript.jsonl`. This command assumes you have copied the actual dump to that local filename. Check final words, participant IDs and persistence after recreation. [S9]

## If it still fails

Look for `Unable to write transcript to file `, `Was unable to make a directory called ` or `Could not execute ` in transcriber logs. Package logs are `/var/log/jitsi/jigasi.log`. Inspect ownership, effective custom properties, CLI availability, credentials and each directory's `s3-upload.log`. There is no built-in upload retry; rerun the script against a failed directory after fixing the cause. [S3][S6][S7][S8]

For missing speech or XMPP errors, use [transcription troubleshooting](/troubleshooting/jitsi-transcription-not-working/). [S11]

## FAQ

### Does SEND_TXT send the transcript file to participants?

It sends recognized speech to meeting chat. File delivery requires a separate authenticated download or your application workflow. [S3]

### Can I save captions from an embedded meeting?

Stable-11248 exposes `transcriptionChunkReceived` with `{ data }`; final text is `data.final`, while `data.stable` is still interim. Capture final messages in your app and handle reconnection, deduplication and permission checks. [S9][S12]

### Does the bridge replacement save the same TXT file?

No. Its optional dump is JSONL of final provider messages, not Jigasi's complete transcript format or an automatic download service. For managed delivery, see our [transcription setup service](/services/jitsi-transcription/). [S9][S11]

## Sources

All checked 2026-10-06.

[S1] [Latest release](https://github.com/jitsi/docker-jitsi-meet/releases/latest), [current transcriber](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11248/transcriber.yml), [web volumes](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11248/docker-compose.yml), [transcription template](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11248/jigasi/rootfs/defaults/transcriber-sip-communicator.properties), [Docker handbook](https://jitsi.github.io/handbook/docs/devops-guide/devops-guide-docker/), stable-11248 released 2026-09-14, release note/source code/official doc.

[S2] [stable-11031 overlay](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11031/transcriber.yml), [old web volumes](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11031/docker-compose.yml), [rootless PR #2258](https://github.com/jitsi/docker-jitsi-meet/pull/2258), [stable-11146](https://github.com/jitsi/docker-jitsi-meet/releases/tag/stable-11146), 2026-08-03 release, source code/release note.

[S3] Released Jigasi [flags](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/src/main/java/org/jitsi/jigasi/transcription/TranscriptHandler.java), [publisher](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/src/main/java/org/jitsi/jigasi/transcription/AbstractTranscriptPublisher.java), [TXT](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/src/main/java/org/jitsi/jigasi/transcription/LocalTxtTranscriptHandler.java), [JSON](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/src/main/java/org/jitsi/jigasi/transcription/LocalJsonTranscriptHandler.java), [final filter](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/src/main/java/org/jitsi/jigasi/transcription/Transcript.java), [session end](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/src/main/java/org/jitsi/jigasi/TranscriptionGatewaySession.java), 2026-09-11 snapshot, source code.

[S4] Docker [Nginx route](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11248/web/rootfs/defaults/meet.conf), [web config copy](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11248/web/rootfs/etc/s6-overlay/scripts/config), [Nginx launch](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11248/web/rootfs/etc/s6-overlay/scripts/nginx), stable-11248, source code.

[S5] Docker [custom properties](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11248/jigasi/rootfs/etc/s6-overlay/scripts/config), [Jigasi image](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11248/jigasi/Dockerfile), [apt wrapper](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11248/base/rootfs/usr/bin/apt-dpkg-wrap), [cleanup](https://github.com/jitsi/docker-jitsi-meet/blob/stable-11248/base/rootfs/usr/bin/apt-cleanup), stable-11248, source code.

[S6] Jigasi [package index](https://download.jitsi.org/stable/Packages), [installed paths](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/debian/install), [ownership](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/debian/postinst), [service](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/debian/jigasi.service), package 1.1-415, official repository/source code.

[S7] [Script invocation](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/src/main/java/org/jitsi/jigasi/transcription/AbstractTranscriptPublisher.java#L747-L773), source code; [Docker PR #2225](https://github.com/jitsi/docker-jitsi-meet/pull/2225), closed 2026-06-07, unmerged proposal.

[S8] AWS [upload](https://docs.aws.amazon.com/cli/latest/reference/s3/cp.html), [listing](https://docs.aws.amazon.com/cli/latest/reference/s3/ls.html), [CLI installation](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html), [CLI environment](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-envvars.html), [roles](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-role.html), [container metadata](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-options.html), [public-access blocking](https://docs.aws.amazon.com/AmazonS3/latest/userguide/access-control-block-public-access.html), [lifecycle](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html), [Debian awscli](https://packages.debian.org/trixie/awscli), official docs/package index.

[S9] Bridge proxy [dump documentation](https://github.com/jitsi/opus-transcriber-proxy/blob/6747f187c0e7f4fa17f7744e0d76a5ce6d7d4b24/WEBSOCKET_DUMP.md), [capture code](https://github.com/jitsi/opus-transcriber-proxy/blob/6747f187c0e7f4fa17f7744e0d76a5ce6d7d4b24/src/transcriberproxy.ts), [image](https://github.com/jitsi/opus-transcriber-proxy/blob/6747f187c0e7f4fa17f7744e0d76a5ce6d7d4b24/Dockerfile), 2026-10-05 snapshot; Meet [caption event](https://github.com/jitsi/jitsi-meet/blob/stable/jitsi-meet_11248/react/features/subtitles/middleware.ts), [payload](https://github.com/jitsi/jitsi-meet/blob/stable/jitsi-meet_11248/react/features/subtitles/functions.web.ts), source code/official doc.

[S10] [Docker CLI](https://docs.docker.com/reference/cli/docker/), [Nginx location](https://nginx.org/en/docs/http/ngx_http_core_module.html#location), [return](https://nginx.org/en/docs/http/ngx_http_rewrite_module.html#return), [switches](https://nginx.org/en/docs/switches.html), [coreutils](https://manpages.debian.org/trixie/coreutils/), [find](https://manpages.debian.org/trixie/findutils/find.1.en.html), [systemctl](https://www.freedesktop.org/software/systemd/man/latest/systemctl.html), [curl](https://curl.se/docs/manpage.html), [shell](https://manpages.debian.org/trixie/dash/dash.1.en.html), official docs.

[S11] jitsi.help [Vosk](/guides/jitsi-transcription-vosk/), [bridge](/guides/jitsi-bridge-transcription-opus-proxy/), [troubleshooting](/troubleshooting/jitsi-transcription-not-working/), [service](/services/jitsi-transcription/), independent guides.

[S12] Meet [client configuration](https://github.com/jitsi/jitsi-meet/blob/stable/jitsi-meet_11248/config.js), [event test](https://github.com/jitsi/jitsi-meet/blob/stable/jitsi-meet_11248/tests/specs/jaas/transcriptions.spec.ts#L199), stable-11248; Jigasi [README](https://github.com/jitsi/jigasi/blob/2750d5448271a7a421cb28a914970a4383127380/README.md#L328-L348), 2026-09-11 snapshot, source code/official repository docs.

## Open questions

Real meeting saves, the derived AWS image, end-to-end S3 delivery and proxy restart persistence need server testing. No stock hook retry, per-meeting download authorization, or automatic bridge TXT export was verified. Test custom routing and purge any previously cached public transcript copies. [S3][S4][S7][S8][S9]

---

Jitsi Help is an independent service. It is not affiliated with, endorsed by or sponsored by 8x8, Inc. or the Jitsi project. Jitsi and Jitsi Meet are trademarks of 8x8, Inc., used here only to describe the software we host and support.
