aws-sandbox.orgOne AWS service and one hands-on lab a day. Independent; not affiliated with AWS.
Tuesday, November 3, 2026AssociateAI and ML

Polly and Transcribe: turn text into speech, then speech back into text

Amazon Polly reads text aloud and Amazon Transcribe writes speech down. Today: what each one is for, the October upgrade to Polly's Generative voices, and a lab that does a full round trip through one S3 bucket.

Amazon Polly with Amazon Transcribe, in plain words

Amazon Polly is text-to-speech: you send words, it returns audio. It has four engines with different quality and prices: standard, neural, long-form and generative, the most natural-sounding one. A quick request with SynthesizeSpeech returns audio right away but handles at most 3,000 characters. For longer text, StartSpeechSynthesisTask runs in the background and writes the audio file into an S3 bucket you choose (up to 100,000 billable characters per task).

Amazon Transcribe is the opposite: speech-to-text. A batch job reads an audio or video file from S3 (MP3, WAV, FLAC, MP4 and more), and writes a JSON transcript with the full text plus a timestamp and confidence score for each word. You can name the language, or let Transcribe detect it. If you don't give it an output bucket, the transcript goes to a bucket AWS manages, and you only get a download link that expires after 15 minutes.

Used together through Amazon S3, they make a handy round trip for testing voice features: generate a known sentence with Polly, transcribe it, and compare. In news: on October 20, 2026 AWS upgraded the model behind Polly's Generative engine for more natural speech, added 14 voices (including the US English voices Kenneth and Nate) and brought Hindi and Finnish to that engine for the first time. Existing SSML keeps working, but the docs warn that model updates can slightly change how a voice sounds.

Reach for it when

  • You want to add spoken output to an app, such as reading articles aloud, phone-menu prompts or accessibility audio, and you'd rather pay per character than record a voice actor.
  • You have recorded calls, meetings, podcasts or videos in S3 and need searchable text, captions or input for a summary.
  • You are testing a voice workflow and want repeatable sample audio: Polly creates the same sentence on demand, and Transcribe checks what a listener (or a downstream model) would hear.

Skip it when

  • You need a specific person's voice or your own brand voice. Polly gives you a fixed list of voices to choose from, so a custom voice is outside what this lab or the standard API covers.
  • You need live, back-and-forth conversation with very low delay. Batch jobs take seconds to minutes; look at Polly's streaming APIs and Transcribe's streaming transcription instead.
  • The audio is already human-transcribed or you only need a few minutes once. Typing it up or using a tool you already have may be simpler than setting up buckets and jobs.

The AI angle

Polly and Transcribe are the ears and mouth around a language model. A typical voice assistant on AWS transcribes what the user says, sends the text to a model in Amazon Bedrock, and has Polly speak the reply. Transcripts are also common inputs for Bedrock summaries or a Knowledge Base, so a meeting recording can become searchable notes. Treat transcripts as untrusted input when you pass them to a model, because the speaker controls what is said.

Hands-on lab: Round trip: Polly speaks a sentence into S3, Transcribe writes it back down

From AWS CloudShell, create a private S3 bucket, have Polly turn one sentence into an MP3 in that bucket with a Generative voice, have Transcribe turn the MP3 back into text in the same bucket, compare the two, and then delete everything.

TIMEAbout 15 minutes (including two short waits)
COSTA fraction of one cent. The sentence is about 150 characters; at the Generative price on the Polly pricing page ($30 per 1 million characters) that is well under one cent. Transcribe bills batch jobs per second with no minimum according to its pricing page, and a ten-second clip costs a tiny fraction of a cent. S3 storage for two small files for a few minutes is negligible.
FREE TIER / CREDITSThe Polly pricing page lists 100,000 Generative characters a month for the first 12 months, and the Transcribe pricing page lists 60 minutes a month for 12 months. Accounts created on or after July 15, 2025 use the newer credit-based Free Tier instead; this lab uses a few cents of credit at most.

Before you start

  • A sandbox AWS account you own, signed in to the console with a user or role that may use Amazon S3, Amazon Polly and Amazon Transcribe.
  • AWS CloudShell open in a Region where Polly's Generative engine is available, such as US East (N. Virginia) or US West (Oregon). In other Regions, change --engine generative to --engine neural in step 2.
  • No access keys needed: CloudShell uses your console sign-in.
  1. Set names and create a private bucket

    Pick a Region and a unique bucket name. New S3 buckets block public access by default, and nothing in this lab changes that. The sentence is saved to a file so you can compare it later.

    REGION=${AWS_REGION:-us-east-1}
    BUCKET=voice-lab-$(date +%s)-$RANDOM
    JOB=voice-lab-job-$(date +%s)
    echo "Region: $REGION  Bucket: $BUCKET  Job: $JOB"
    
    aws s3 mb s3://$BUCKET --region $REGION
    
    echo 'Welcome to the sandbox. Today we turn this sentence into speech, then back into text, and check that both versions match.' > original.txt
  2. Ask Polly to write the speech into S3

    start-speech-synthesis-task runs in the background and saves the MP3 in your bucket under a key that ends with the task ID. Ruth is one of the US English Generative voices.

    TASK_ID=$(aws polly start-speech-synthesis-task \
      --region $REGION \
      --engine generative \
      --voice-id Ruth \
      --output-format mp3 \
      --output-s3-bucket-name $BUCKET \
      --output-s3-key-prefix speech/ \
      --text file://original.txt \
      --query 'SynthesisTask.TaskId' --output text)
    echo "Polly task: $TASK_ID"
  3. Wait for Polly and find the audio file

    Check the task until it says completed (usually a few seconds; if it says failed, run aws polly get-speech-synthesis-task --region $REGION --task-id $TASK_ID to read TaskStatusReason). The task reports the file's address as OutputUri; the part after the bucket name is the S3 key.

    while true; do
      PSTATUS=$(aws polly get-speech-synthesis-task --region $REGION --task-id $TASK_ID \
        --query 'SynthesisTask.TaskStatus' --output text)
      echo "Polly: $PSTATUS"
      [ "$PSTATUS" = "completed" ] || [ "$PSTATUS" = "failed" ] && break
      sleep 5
    done
    
    URI=$(aws polly get-speech-synthesis-task --region $REGION --task-id $TASK_ID \
      --query 'SynthesisTask.OutputUri' --output text)
    KEY=${URI#*/$BUCKET/}
    echo "Audio key: $KEY"
    aws s3 ls s3://$BUCKET --recursive
  4. Start a Transcribe job on that MP3

    Transcribe reads the file from the same bucket and writes its JSON result under transcripts/. The bucket must be in the same Region as the job, which it is here.

    aws transcribe start-transcription-job \
      --region $REGION \
      --transcription-job-name $JOB \
      --language-code en-US \
      --media MediaFileUri=s3://$BUCKET/$KEY \
      --media-format mp3 \
      --output-bucket-name $BUCKET \
      --output-key transcripts/ \
      --query 'TranscriptionJob.TranscriptionJobStatus' --output text
  5. Wait for Transcribe and read the transcript

    Batch jobs usually finish within a minute for a clip this short. When the status is COMPLETED, download the JSON and print the text next to the original.

    while true; do
      STATUS=$(aws transcribe get-transcription-job --region $REGION --transcription-job-name $JOB \
        --query 'TranscriptionJob.TranscriptionJobStatus' --output text)
      echo "Transcribe: $STATUS"
      [ "$STATUS" = "COMPLETED" ] || [ "$STATUS" = "FAILED" ] && break
      sleep 10
    done
    
    TKEY=$(aws s3api list-objects-v2 --bucket $BUCKET --prefix transcripts/ \
      --query 'Contents[?ends_with(Key, `.json`)].Key | [0]' --output text)
    aws s3 cp s3://$BUCKET/$TKEY transcript.json
    
    echo 'Original:'; cat original.txt
    echo 'Transcript:'
    python3 -c "import json; print(json.load(open('transcript.json'))['results']['transcripts'][0]['transcript'])"
  6. Optional: listen to the voice

    Copy the MP3 into CloudShell, then use Actions > Download file in CloudShell with the path speech.mp3 to play it on your computer.

    aws s3 cp s3://$BUCKET/$KEY speech.mp3
    ls -l speech.mp3

Check that it worked

Step 3 shows completed and an OutputUri in your bucket, step 5 shows COMPLETED, and the transcript matches the original sentence word for word or with only small differences in punctuation.

Clean up

Delete the transcription job record, empty and remove the bucket (the MP3, the transcript and anything else Transcribe wrote there), and remove the local files. Polly tasks can't be deleted and need no cleanup: they are only a status record, and the CLI reference says a task stays available for 72 hours. The last commands should print Bucket gone and an empty list for the job.

aws transcribe delete-transcription-job --region $REGION --transcription-job-name $JOB
aws s3 rm s3://$BUCKET --recursive
aws s3 rb s3://$BUCKET
rm -f original.txt transcript.json speech.mp3

# Confirm nothing is left
aws s3 ls | grep "$BUCKET" || echo 'Bucket gone'
aws transcribe list-transcription-jobs --region $REGION --job-name-contains voice-lab \
  --query 'TranscriptionJobSummaries[].TranscriptionJobName'

Gotchas

  • Not every voice works with every engine or Region. Asking for a voice the chosen engine doesn't support returns an error, and the Generative engine is offered only in a listed set of Regions. Check the voice list before you hard-code a voice ID.
  • Without --output-bucket-name, Transcribe stores the transcript in an AWS-managed bucket for 90 days and hands you a link that expires in 15 minutes. For anything you want to keep, write to your own bucket.
  • Transcription job names must be unique in your account and Region, and can't contain spaces. Reusing a name fails with a conflict error, so add a timestamp or delete the old job first.
  • Polly's Generative voices don't produce speech marks (the word timing data used for lip-sync or highlighting) and don't have the newscaster style. Use a neural voice if you need those.
  • Generative voices can change slightly when AWS updates the model, as it did in October 2026. If you produce audio in batches over months, such as a podcast season, listen for drift between batches.