---
title: Analyze Text
description: On-device sentiment, toxicity and moderation of text
---

Score text for sentiment, toxicity or other moderation labels with a model that runs in your browser, so the text never leaves your device.

## What it does

Analyze Text runs the **Text** through the text-moderation model you pick and returns every label the model knows, with a confidence score from 0 to 1. The labels come from the model: *DistilBERT SST-2 (sentiment)* gives positive and negative, while *toxic-bert* and the TensorFlow.js *Toxicity* model give toxicity categories.

Labels scoring below **Confidence threshold** are dropped, the rest are sorted best first and cut to **Top-K labels**. There is no cost per run and no API key.

## When to use it

* Flag toxic comments or messages before you post or forward them.
* Gauge the tone of customer feedback and route negative replies to a person.
* Gate a branch on a score, for example only continue when the text is not toxic.

To sort text into labels you choose yourself (billing, bug report, other), use [Classify Text](/nodes/builtin/ai/localai/classify-text/) instead.

## Inputs and settings

* **Model**: pick *DistilBERT SST-2 (sentiment)* for positive/negative, or *toxic-bert* or *Toxicity* for moderation. The picker also lists the *DeBERTa zero-shot* model, which needs your own labels: use it with Classify Text, not here.
* **Confidence threshold**: the default 0 keeps every label. Set it to 0.5 to keep only labels the model is fairly sure about.
* **Text**: usually an expression, such as `{{ $input.selectionText }}`.

## Outputs

Each output item has these fields:

```json title="Shape of an output item"
{
  "predictions": [],
  "top": "…",
  "score": 0
}
```

Each entry in `predictions` is `{ label, score }`. `score` is the score of `top`. Branch on `{{ $input.top }}` for a simple yes/no, or on `{{ $input.score }}` when you want your own cut-off.

## Dependencies and credentials

None. This node needs no connection and has no slots for other nodes.

The node needs a local model instead. The **Model** picker lists your installed models first, then models that download on first use. To download ahead of time, or to free space later, use the [Local AI](/app/local-models/) page.

## Example workflow

Check the tone of text you select on a page:

1. [Context Menu](/nodes/builtin/trigger/contextmenu/) with **Menu Contexts** set to **Selection**.
2. Analyze Text with **Model** *DistilBERT SST-2 (sentiment)* and **Text** `{{ $input.selectionText }}`.
3. [Show Notification](/nodes/extension/shownotification/) with **Title** `Tone` and **Message** `{{ $input.top }} ({{ $input.score }})`.

## Common issues

* **"Choose a model to analyze with."** **Model** is empty. Pick one; models under **Available** download on first use.
* **"Provide some text to analyze."** **Text** is empty after expressions run. Check that the field you point to exists in the incoming data.
* **"Zero-shot classification needs at least one candidate label."** You picked *DeBERTa zero-shot*. Use a sentiment or toxicity model here, or switch to Classify Text.
* **`top` is null.** No label reached **Confidence threshold**. Lower it.
* **The first run is slow.** The model downloads and loads on first use, then later runs are fast.

## Related nodes

* [Classify Text](/nodes/builtin/ai/localai/classify-text/): sort text into your own labels.
* [Sentiment Analysis](/nodes/builtin/ai/aiagents/sentimentanalysisnode/): sentiment with a chat model.
* [Switch](/nodes/builtin/flow/switch/): route items by the `top` label.
* [Run Local Model](/nodes/builtin/ai/localai/run-local-model/): run any installed model for any task.