<br />

The MediaPipe Text Embedder task lets you create a numeric representation of text data to
capture its semantic meaning. This functionality is frequently used to compare
the semantic similarity of two pieces of text using mathematical comparison
techniques such as Cosine Similarity. This task operates on text data with a
machine learning (ML) model, and outputs a numeric representation of the text
data as a list of high-dimensional feature vectors, also known as embedding
vectors, in either floating-point or quantized form.


<iframe class="mp-demo-frame mp-demo-frame--studio" aria-label="Text Embedder interactive Web SDK demo" loading="lazy" data-src="https://developers.devsite.google/frame/edge/mediapipe/demos/embed/text_embedder.jshtml" allow="camera *; microphone *"></iframe>

[Open in Web Demos](https://google-ai-edge.github.io/mediapipe-samples-web/#/text/text_embedder)[Edit in StackBlitz](https://stackblitz.com/github/google-ai-edge/mediapipe-samples-web?file=src/tasks/text-embedder.ts)

<br />

## Quickstart

Install the SDK for your platform, initialize the task with a model, and run
inference.

### Web

npm`npm install @mediapipe/tasks-text`[Web demo](https://google-ai-edge.github.io/mediapipe-samples-web/#/text/text_embedder)·[Edit in StackBlitz](https://stackblitz.com/github/google-ai-edge/mediapipe-samples-web?file=src/tasks/text-embedder.ts)·[Setup guide](https://developers.google.com/edge/mediapipe/solutions/setup_web.md.txt)

```typescript
import { FilesetResolver, TextEmbedder } from "@mediapipe/tasks-text";

const MODEL_URL = "https://storage.googleapis.com/mediapipe-models/text_embedder/universal_sentence_encoder/float32/latest/universal_sentence_encoder.tflite";

const textFiles = await FilesetResolver.forTextTasks(
  "https://cdn.jsdelivr.net/npm/@mediapipe/tasks-text@latest/wasm"
);
const textEmbedder = await TextEmbedder.createFromOptions(textFiles, {
  baseOptions: { modelAssetPath: MODEL_URL },
  quantize: true,
});

const firstEmbed = textEmbedder.embed("It's a charming and affecting journey.").embeddings[0];
const secondEmbed = textEmbedder.embed("What a great and fantastic trip!").embeddings[0];
const similarity = TextEmbedder.cosineSimilarity(firstEmbed, secondEmbed);
```

### Android (Kotlin)

Gradle`implementation("com.google.mediapipe:tasks-text:latest.release")`[Sample code](https://github.com/google-ai-edge/mediapipe-samples/tree/main/examples/text_embedder/android)·[Setup guide](https://developers.google.com/edge/mediapipe/solutions/setup_android.md.txt)

```kotlin
import com.google.mediapipe.tasks.core.BaseOptions
import com.google.mediapipe.tasks.text.textembedder.TextEmbedder
import com.google.mediapipe.tasks.text.textembedder.TextEmbedder.TextEmbedderOptions

val baseOptions = BaseOptions.builder()
    .setModelAssetPath("universal_sentence_encoder.tflite")
    .build()
val options = TextEmbedderOptions.builder()
    .setBaseOptions(baseOptions)
    .setQuantize(true)
    .build()

val textEmbedder = TextEmbedder.createFromOptions(context, options)

val firstEmbed = textEmbedder
    .embed("It's a charming and affecting journey.")
    .embeddingResult().embeddings().first()
val secondEmbed = textEmbedder
    .embed("What a great and fantastic trip!")
    .embeddingResult().embeddings().first()
val similarity = TextEmbedder.cosineSimilarity(firstEmbed, secondEmbed)
```

### Android (Java)

Gradle`implementation 'com.google.mediapipe:tasks-text:latest.release'`[Sample code](https://github.com/google-ai-edge/mediapipe-samples/tree/main/examples/text_embedder/android)·[Setup guide](https://developers.google.com/edge/mediapipe/solutions/setup_android.md.txt)

```java
import com.google.mediapipe.tasks.components.containers.Embedding;
import com.google.mediapipe.tasks.core.BaseOptions;
import com.google.mediapipe.tasks.text.textembedder.TextEmbedder;
import com.google.mediapipe.tasks.text.textembedder.TextEmbedder.TextEmbedderOptions;

BaseOptions baseOptions = BaseOptions.builder()
    .setModelAssetPath("universal_sentence_encoder.tflite")
    .build();
TextEmbedderOptions options = TextEmbedderOptions.builder()
    .setBaseOptions(baseOptions)
    .setQuantize(true)
    .build();

TextEmbedder textEmbedder = TextEmbedder.createFromOptions(context, options);

Embedding firstEmbed = textEmbedder
    .embed("It's a charming and affecting journey.")
    .embeddingResult().embeddings().get(0);
Embedding secondEmbed = textEmbedder
    .embed("What a great and fantastic trip!")
    .embeddingResult().embeddings().get(0);
double similarity = TextEmbedder.cosineSimilarity(firstEmbed, secondEmbed);
```

### iOS

SwiftPM`https://github.com/google-ai-edge/mediapipe → MediaPipeTasksText`[Package.swift](https://developers.google.com/edge/mediapipe/solutions/setup_ios.md.txt#package_swift)·[Sample code](https://github.com/google-ai-edge/mediapipe-samples/tree/main/examples/text_embedder/ios)·[Setup guide](https://developers.google.com/edge/mediapipe/solutions/setup_ios.md.txt)

```swift
import Foundation
import MediaPipeTasksText

guard let modelPath = Bundle.main.path(
    forResource: "universal_sentence_encoder",
    ofType: "tflite"
) else { return }

let options = TextEmbedderOptions()
options.baseOptions.modelAssetPath = modelPath
options.quantize = true

let textEmbedder = try TextEmbedder(options: options)

let firstResult = try textEmbedder.embed(text: "It's a charming and affecting journey.")
let secondResult = try textEmbedder.embed(text: "What a great and fantastic trip!")
if let firstEmbed = firstResult.embeddingResult.embeddings.first,
   let secondEmbed = secondResult.embeddingResult.embeddings.first {
    let similarity = try TextEmbedder.cosineSimilarity(embedding1: firstEmbed, embedding2: secondEmbed)
}
```

### Python

pip`pip install mediapipe`[Sample code](https://colab.research.google.com/github/google-ai-edge/mediapipe-samples/blob/main/examples/text_embedder/python/text_embedder.ipynb)·[Setup guide](https://developers.google.com/edge/mediapipe/solutions/setup_python.md.txt)

```python
import mediapipe as mp

BaseOptions = mp.tasks.BaseOptions
TextEmbedder = mp.tasks.text.TextEmbedder
TextEmbedderOptions = mp.tasks.text.TextEmbedderOptions

model_path = "universal_sentence_encoder.tflite"
options = TextEmbedderOptions(base_options=BaseOptions(model_asset_path=model_path), quantize=True)

with TextEmbedder.create_from_options(options) as text_embedder:
    first_embed = text_embedder.embed("It's a charming and affecting journey.").embeddings[0]
    second_embed = text_embedder.embed("What a great and fantastic trip!").embeddings[0]
    similarity = TextEmbedder.cosine_similarity(first_embed, second_embed)
```

### Flutter

pub`flutter pub add mediapipe_text`[Live gallery](https://google.github.io/flutter-mediapipe/)·[Sample code](https://github.com/google/flutter-mediapipe/tree/main/samples/text/text_embedder)·[Setup guide](https://developers.google.com/edge/mediapipe/solutions/setup_flutter.md.txt)

```dart
import 'package:mediapipe_text/mediapipe_text.dart';

Future<double> compareSentences(String first, String second) async {
  final embedder = await TextEmbedder.create(
    TextEmbedderOptions(model: TextModels.universalSentenceEncoder),
  );
  try {
    final a = await embedder.embed(first);
    final b = await embedder.embed(second);
    return TextEmbedder.cosineSimilarity(
      a.embeddings.first,
      b.embeddings.first,
    );
  } finally {
    await embedder.dispose();
  }
}
```

## Task details

This section describes the capabilities, inputs, outputs, and configuration
options of this task.

### Features

- **Input text processing** - Supports out-of-graph tokenization for models without in-graph tokenization.
- **Embedding similarity computation** - Built-in utility function to compute the [cosine similarity](https://en.wikipedia.org/wiki/Cosine_similarity) between two feature vectors.
- **Quantization** - Supports scalar quantization for the feature vectors.

Inputs Text Embedder accepts the following input for processing:

- Text (`String`)
- Optional formatting context (`TextFormatOptions` on Web, `TextFormatContext` on Android, iOS, and Flutter, or `TextEmbeddingFormatContext` in Python) for supported models like the EmbeddingGemma 300M model.
Outputs The Text Embedder outputs a list of embeddings consisting of:

- Embedding: the feature vector itself, either in floating-point form or scalar-quantized.
- Head index: the index for the head that produced this embedding.
- Head name (optional): the name of the head that produced this embedding.

### Configuration options

This task has the following configuration options:

### Web

| Option Name | Description | Value Range | Default Value |
|---|---|---|---|
| `l2Normalize` | Whether to normalize the returned feature vector with L2 norm. Use only if the model does not already include a built-in `L2_NORMALIZATION` op. | `Boolean` | `false` |
| `quantize` | Whether to scalar-quantize the returned embedding to bytes (assumes unit-norm vectors in `[-1.0, 1.0]`; pair with `l2Normalize` if needed). | `Boolean` | `false` |

### Android

| Option Name | Description | Value Range | Default Value |
|---|---|---|---|
| `l2Normalize` | Whether to normalize the returned feature vector with L2 norm. Use only if the model does not already include a built-in `L2_NORMALIZATION` op. | `Boolean` | `false` |
| `quantize` | Whether to scalar-quantize the returned embedding to bytes (assumes unit-norm vectors in `[-1.0, 1.0]`; pair with `l2Normalize` if needed). | `Boolean` | `false` |

### iOS

| Option Name | Description | Value Range | Default Value |
|---|---|---|---|
| `l2Normalize` | Whether to normalize the returned feature vector with L2 norm. Use only if the model does not already include a built-in `L2_NORMALIZATION` op. | `Boolean` | `false` |
| `quantize` | Whether to scalar-quantize the returned embedding to bytes (assumes unit-norm vectors in `[-1.0, 1.0]`; pair with `l2Normalize` if needed). | `Boolean` | `false` |

### Python

| Option Name | Description | Value Range | Default Value |
|---|---|---|---|
| `l2_normalize` | Whether to normalize the returned feature vector with L2 norm. Use only if the model does not already include a built-in `L2_NORMALIZATION` op. | `Boolean` | `False` |
| `quantize` | Whether to scalar-quantize the returned embedding to bytes (assumes unit-norm vectors in `[-1.0, 1.0]`; pair with `l2_normalize` if needed). | `Boolean` | `False` |

### Flutter

| Option Name | Description | Value Range | Default Value |
|---|---|---|---|
| `l2Normalize` | Whether to normalize the returned feature vector with L2 norm. Use only if the model does not already include a built-in `L2_NORMALIZATION` op. | `bool` | `false` |
| `quantize` | Whether to scalar-quantize the returned embedding to bytes (assumes unit-norm vectors in `[-1.0, 1.0]`; pair with `l2Normalize` if needed). | `bool` | `false` |

### Task output

Each `TextEmbedderResult` returns an `embeddings` list, and `cosineSimilarity` (`cosine_similarity`) computes semantic similarity between two embeddings in `[-1.0, 1.0]`:

| Field | Type / Range | Description |
|---|---|---|
| `floatEmbedding` | `Float32Array` / `float[]` | Dense float semantic vector (`embedding` in Python; L2-normalized when `l2Normalize` is enabled; in Dart, a `Float32List?` that is `null` when `quantize` is enabled). |
| `quantizedEmbedding` | `Uint8Array` / `byte[]` | Scalar-quantized 8-bit vector when `quantize` is enabled (in Dart, a `Uint8List?` holding signed 8-bit values). |
| `headIndex` | `int` | Zero-based index of the embedding head (`head_index` in Python). |
| `headName` | `string` | Optional name of the embedding head (`head_name` in Python). |

#### Example `TextEmbedderResult` payload

The following example shows the dense float embedding vector returned for an input string:

```javascript
{
  embeddings: [
    {
      headIndex: 0,
      floatEmbedding: [0.2345, 0.1234, -0.0891, 0.4102, 0.6789 /* ... */]
    }
  ]
}
```

## Models

![Text Embedder pipeline overview](https://developers.google.com/static/edge/mediapipe/images/solutions/diagrams/text_embedder.svg)

The Text Embedder supports the smaller Universal Sentence Encoder model and the
more capable EmbeddingGemma 300M model for advanced use cases.

### EmbeddingGemma 300M model

The TextEmbedder SDK supports the
[embeddinggemma-300m](https://huggingface.co/litert-community/embeddinggemma-300m).
The provided task file uses a maximum sequence length of 512 tokens.

This model handles input differently based on the task type and context format
you provide. For the query formats, the template follows `task: <task> | query:
<text>`, and for document formats, it follows
`title: <title> | text: <text>`. The formats follow the official EmbeddingGemma
[prompt
instruction](https://huggingface.co/google/embeddinggemma-300m#prompt-instructions).

| Task Type | Formatting |
|---|---|
| `RETRIEVAL_DOCUMENT` | Uses document format with the provided title. |
| `RETRIEVAL_QUERY` | Uses query format with `<task>` as "search result". |
| `SEMANTIC_SIMILARITY` | Uses query format with `<task>` as "sentence similarity". |
| `CLASSIFICATION` | Uses query format with `<task>` as "classification". |
| `CLUSTERING` | Uses query format with `<task>` as "clustering". |
| `QUESTION_ANSWERING` / `FACT_CHECKING` / `CODE_RETRIEVAL` | Depending on whether the role is a query or document, it uses the respective format. When acting as a query, the `<task>` string corresponds to "question answering", "fact checking", or "code retrieval" respectively. |
| **Default** | Any other task type falls back to the query format with `<task>` as "search result". |

| Model name | Input | Quantization type | Versions |
|---|---|---|---|
| [EmbeddingGemma 300M](https://storage.googleapis.com/mediapipe-models/text_embedder/embedding_gemma/int4int8/latest/embedding_gemma.task) | string | Mixed Precision (int4+int8) | [Latest](https://storage.googleapis.com/mediapipe-models/text_embedder/embedding_gemma/int4int8/latest/embedding_gemma.task) |

### Universal Sentence Encoder model

This model uses a [dual encoder
architecture](https://aclanthology.org/2022.emnlp-main.640.pdf) and was trained
on various question-answer datasets.

Consider the following pairs of sentences:

- ("it's a charming and often affecting journey", "what a great and fantastic trip")
- ("I like my phone", "I hate my phone")
- ("This restaurant has a great gimmick", "We need to double-check the details of our plan")

The text embeddings in the first two pairs will have a higher cosine similarity
than the embeddings in the third pair because the first two pairs of sentences
share a common topic of "trip sentiment" and "phone opinion" respectively while
the third pair of sentences don't share a common topic.

Note that although the two sentences in the second pair have opposing
sentiments, they have a high similarity score because they share a common topic.

| Model name | Input | Quantization type | Versions |
|---|---|---|---|
| [Universal Sentence Encoder](https://storage.googleapis.com/mediapipe-models/text_embedder/universal_sentence_encoder/float32/latest/universal_sentence_encoder.tflite) | string, string, string | None (float32) | [Latest](https://storage.googleapis.com/mediapipe-models/text_embedder/universal_sentence_encoder/float32/latest/universal_sentence_encoder.tflite) |

## Task benchmarks

Here are the task benchmarks for the whole pipeline based on the preceding
pre-trained models. The latency result is the average latency on Samsung S26
Ultra CPU with 4 threads. For more detailed benchmarks, see the
[EmbeddingGemma model card](https://huggingface.co/litert-community/embeddinggemma-300m#performance).

| Model name | Device | CPU latency (ms) |
|---|---|---|
| Universal Sentence Encoder | Galaxy S26 Ultra (4 threads) | 10 |
| EmbeddingGemma 300M | Galaxy S26 Ultra (4 threads) | 200 |