Comprehend via SDK Best Practices
This is the checklist to run before and after taking a Comprehend workload to production from the SDK.
Search across all documentation pages
This is the checklist to run before and after taking a Comprehend workload to production from the SDK.
Each item is a rule stated positively, with a one-line rationale. Work top to bottom - the groups run from language and input handling, through the real-time-vs-batch decision, to PII/security, custom models, cost, and operations. Most rules apply whether you call Comprehend from boto3 or the AWS SDK v3.
DetectDominantLanguage first and feed its result into LanguageCode for DetectSentiment/DetectEntities - a wrong code degrades accuracy without raising an error.BeginOffset/EndOffset index into the exact string you sent - slice that same string to recover the matched substring.Detect language first whenever the input source isn't guaranteed to be one language.
# --- Python (boto3) ---
import boto3
comprehend = boto3.client("comprehend")
text = "Merci pour votre reponse rapide."
# Detect language before scoring - a wrong LanguageCode silently hurts accuracy.
top = max(comprehend.detect_dominant_language(Text=text)["Languages"], key=lambda l: l["Score"])
sentiment = comprehend.detect_sentiment(Text=text, LanguageCode=top["LanguageCode"])// --- TypeScript (AWS SDK v3) ---
import { ComprehendClient, DetectDominantLanguageCommand, DetectSentimentCommand } from "@aws-sdk/client-comprehend";
const comprehend = new ComprehendClient({});
const text = "Merci pour votre reponse rapide.";
// Detect language before scoring - a wrong LanguageCode silently hurts accuracy.
const langs = (await comprehend.send(new DetectDominantLanguageCommand({ Text: text }))).Languages ?? [];
const top = langs.reduce((a, b) => (b.Score! > a.Score! ? b : a));
const sentiment = await comprehend.send(new DetectSentimentCommand({ Text: text, LanguageCode: top.LanguageCode }));Start*Job) when nothing is waiting on an immediate answer. It's typically cheaper to operate and avoids a client-side loop over many synchronous calls.Start*Job.Describe*Job on a sane interval with a timeout. There is no push notification for job completion - a tight polling loop wastes calls without speeding anything up.ONLY_REDACTION mode.ContainsPiiEntities at high volume. It's a cheaper check that tells you whether the fuller, offset-returning call is worth running.DataAccessRoleArn should read only the specific input prefix and write only the specific output prefix, not a whole bucket.Redact from offsets working backward so earlier positions stay valid.
# --- Python (boto3) ---
import boto3
comprehend = boto3.client("comprehend")
text = "Contact Dana at dana@example.com."
entities = comprehend.detect_pii_entities(Text=text, LanguageCode="en")["Entities"]
# Mask from the end backward so earlier offsets don't shift.
redacted = text
for e in sorted(entities, key=lambda e: e["BeginOffset"], reverse=True):
redacted = redacted[:e["BeginOffset"]] + f"[{e['Type']}]" + redacted[e["EndOffset"]:]// --- TypeScript (AWS SDK v3) ---
import { ComprehendClient, DetectPiiEntitiesCommand } from "@aws-sdk/client-comprehend";
const comprehend = new ComprehendClient({});
const text = "Contact Dana at dana@example.com.";
const entities = (await comprehend.send(new DetectPiiEntitiesCommand({ Text: text, LanguageCode: "en" }))).Entities ?? [];
// Mask from the end backward so earlier offsets don't shift.
let redacted = text;
for (const e of [...entities].sort((a, b) => b.BeginOffset! - a.BeginOffset!)) {
redacted = redacted.slice(0, e.BeginOffset) + `[${e.Type}]` + redacted.slice(e.EndOffset);
}Status: TRAINED.IN_ERROR model.ContainsPiiEntities before DetectPiiEntities, and language detection before committing to a downstream call, to avoid wasted processing on the wrong path.COMPLETED, FAILED, and STOPPED distinctly rather than only checking for success.Score; decide and document your minimum bar rather than filtering inconsistently across call sites.Treating DetectPiiEntities output as already-redacted text. It only returns types, scores, and offsets - your code (or the async job's redaction mode) does the actual masking.
Yes, whenever the input's language isn't already known with certainty. A wrong LanguageCode doesn't error - it silently applies the wrong language model and degrades accuracy.
Batch, whenever nothing is waiting on an immediate answer. It's typically cheaper to operate and, for custom models, avoids paying for an hourly real-time endpoint between runs.
Delete real-time endpoints you're not actively using - they bill hourly regardless of traffic - and prefer batch jobs for custom-model inference unless traffic is continuous.
A DataAccessRoleArn Comprehend can assume to read your input S3 prefix and write your output S3 prefix. Synchronous calls only need the caller's own permission to invoke the operation.
Apply a consistent minimum Score threshold and route anything below it to a fallback or human review path, rather than trusting a marginal result the same as a high-confidence one.
When you can point at specific documents the pretrained Detect APIs consistently mislabel or miss - not before. Training and, for real-time use, hosting cost more than the pretrained calls.
Stack versions: This page was written for boto3 1.43.x (Python 3.10+) and the AWS SDK for JavaScript v3 (Node.js 18+).
Reviewed by Chris St. John·Last updated Jul 24, 2026