---
title: "Save a speech transcript as JSON in C#"
url: https://recursiveai.org/onespeech/cookbook/save-transcript-as-json/
description: "Save transcript text and metadata as JSON; this example needs no model download."
version: "1.1.0"
---

# Save a speech transcript as JSON in C#

**OneSpeech** is a free, open-source speech recognition library for .NET from Recursive AI. MIT or Apache-2.0, no native dependencies.

[NuGet](https://www.nuget.org/packages/RecursiveAI.OneSpeech) · [GitHub](https://github.com/recursive-ai-oss/onespeech-csharp) · [Docs](https://recursiveai.org/onespeech/docs/) · [Download example (.zip)](https://recursiveai.org/onespeech/cookbook/save-transcript-as-json/save-transcript-as-json.zip)

Save transcript text and metadata as JSON; this example needs no model download.

```shell
dotnet add package RecursiveAI.OneSpeech
```

Requires [.NET 10](https://dotnet.microsoft.com/download/dotnet/10.0) (net10.0); .NET 9 and earlier aren’t supported.

```csharp
using OneSpeech;
var doc = new Transcript { Text = "Hello." };
File.WriteAllText("transcript.json",
    doc.ToJson());
Console.WriteLine("Saved transcript.json.");
```

Unzip [the example](https://recursiveai.org/onespeech/cookbook/save-transcript-as-json/save-transcript-as-json.zip), then `dotnet run`.

Prints:

```text
Saved transcript.json.
```

## The full program

```csharp
using OneSpeech;

var transcript = new Transcript
{
    Text = "Hello.", Language = "en",
    Words = [new Word { Text = "Hello.", TimingMethod = TimingMethod.None }]
};
File.WriteAllText("transcript.json", transcript.ToJson());
var restored = Transcript.FromJson(File.ReadAllText("transcript.json"));
Console.WriteLine("Saved transcript.json.");
Console.WriteLine($"Equal: {transcript == restored}");
Console.WriteLine($"Untimed: {restored.Words[0].Start is null && restored.Words[0].End is null}");
Console.WriteLine($"Speaker not processed: {restored.Words[0].Speaker is null}");
Console.WriteLine($"Provenance entries: {restored.Models.Length}");
```

The full program creates an untimed word, saves it and checks the restored transcript. No audio was recognized, so its model source and license records (provenance) are empty. Invalid documents throw `InvalidTranscriptJsonException`; file I/O errors remain file errors.

```text
Saved transcript.json.
Equal: True
Untimed: True
Speaker not processed: True
Provenance entries: 0
```

The full program writes this `transcript.json` (formatted here for reading):

```json
{
  "schemaVersion": 1,
  "transcript": {
    "text": "Hello.",
    "words": [
      {
        "text": "Hello.",
        "start": null,
        "end": null,
        "confidence": null,
        "timingMethod": "None",
        "speaker": null,
        "overlap": false,
        "language": null
      }
    ],
    "segments": [],
    "turns": [],
    "language": "en",
    "duration": 0,
    "models": []
  }
}
```

## Variations

To use `System.Text.Json` instead, serialize the full program’s `transcript` in one line. No converter registration is needed: `Transcript` carries its converter.

```csharp
string json = System.Text.Json.JsonSerializer.Serialize(transcript);
```

This writes the same schema as `ToJson`. Handle an unsupported schema version:

```csharp
using OneSpeech;
try
{
    Transcript.FromJson("""{"schemaVersion":2,"transcript":{"text":"Hello."}}""");
}
catch (InvalidTranscriptJsonException)
{
    Console.WriteLine("Unsupported transcript schema rejected.");
}
```

```text
Unsupported transcript schema rejected.
```

## Related recipes

- [Serialize with NativeAOT](https://recursiveai.org/onespeech/cookbook/serialize-transcript-with-nativeaot/)
- [Transcribe an audio file](https://recursiveai.org/onespeech/cookbook/transcribe-audio-file/)

## The short answer

Write `transcript.ToJson()` to a file and restore it with `Transcript.FromJson`. OneSpeech uses a versioned JSON envelope—a root object with a schema version and a nested transcript—rather than serializing only the recognized text. It preserves supplied text, timing, speaker labels and model provenance (records of model sources, versions and licenses), and rejects invalid documents instead of repairing missing facts.

The small example constructs “Hello.” rather than running recognition. That keeps file serialization independent of model downloads. In an application, save the `Transcript` returned by recognition through the same methods. The full program adds an untimed word and checks value equality after reading the file back.

## How do I serialize a speech transcript to JSON in C#?

For a OneSpeech `Transcript`, use its explicit methods when you want transcript-specific error types. The root JSON object contains `schemaVersion` and `transcript`; the current major schema is version 1. Text is stored as supplied, not reconstructed from the word array. This matters when written punctuation or whitespace differs from individual word entries.

Nullable timing stays nullable. An untimed word has both start and end set to null, not zero-valued timestamps. Available times are finite, nonnegative seconds encoded as JSON numbers relative to the original audio. Serialization does not align words, identify speakers or improve recognition.

Model provenance records preserve IDs, source URLs, revisions, licenses, attribution and file digests. The constructed example has no model provenance because no model produced it. Real recognition results can carry provenance; saving them preserves those records rather than dropping them. A provenance record does not grant permission to download or redistribute a model.

A null speaker means speaker assignment was not processed. This is different from an explicit unassigned speaker after processing. Keeping that distinction avoids turning “unknown because not attempted” into a claim that an assignment was attempted and failed. The [schema documentation](https://recursiveai.org/onespeech/docs/transcript-json/) defines the fields and validation rules.

## How to turn text into a JSON file?

Construct a transcript with the text you actually have, then use the snippet at the top. Do not populate guessed word boundaries or speaker IDs merely to fill the JSON. Empty arrays are valid, and the format writes null values explicitly. The full example shows how to preserve an untimed word when word-level text is available but alignment is not.

`File.WriteAllText` replaces the named output file. Choose an application-controlled output path and avoid accidentally overwriting another transcript. The serialization call returns a string; file permission and storage errors remain ordinary file errors, separate from transcript validation failures.

## How do I deserialize transcript JSON in C#?

Read the file and pass its contents to `Transcript.FromJson`. Valid transcripts compare by ordered collection values: a round trip preserves equality, including provenance, spacing and null timing. Equality is stricter than comparing the top-level text alone.

Unsupported schema versions, unknown fields, malformed JSON, missing required fields, invalid intervals and exceeded budgets are rejected. Explicit null arrays are also refused; omitted optional arrays retain their empty defaults. The variation supplies an unsupported schema version and catches `InvalidTranscriptJsonException`.

If your application uses `System.Text.Json`, the transcript converter reads and writes the same envelope but reports invalid documents through `JsonException`. For trimmed or NativeAOT applications, register a generated JSON context instead of depending on reflection. Keep application request-body limits appropriate to your memory budget; the library’s maximum document allowance is not an instruction to accept arbitrarily large uploads.
