> ## Content Index
> Fetch the complete content index at: https://www.tool-cloud.com/blog/pt/llms.txt
> Use this file to discover other available public pages before exploring further.

# Como converter texto para Base64 em JavaScript (e decodificar)
- URL: https://www.tool-cloud.com/blog/pt/como-converter-texto-para-base64-em-javascript-e-decodificar/
- Published: 2026-10-14T18:18:34.000Z
- Updated: 2026-10-14T18:28:53.000Z
- Description: A linha de código que funciona, a que gera erro e o motivo — além do ciclo seguro com UTF-8, os métodos nativos de 2025 e as diferenças no Node.js.
- Author: Tool Cloud Team
- Tags: Desenvolvedores, Guias

Para codificar uma string em Base64 em JavaScript, chame `btoa('Hello, world!')`, que retorna `'SGVsbG8sIHdvcmxkIQ=='`. Essa linha única só funciona para texto ASCII e Latin-1: no momento em que você passa um emoji, um acento ou um caractere chinês, ela gera `InvalidCharacterError`. Este guia mostra por que isso acontece e o ciclo seguro com UTF-8 que resolve o problema, incluindo os novos métodos nativos de 2025.

## Base64 em uma linha: btoa() e atob()

A resposta mais rápida: codifique com `btoa('Hello, world!')`, decodifique com `atob('SGVsbG8sIHdvcmxkIQ==')`. Ambos verificados: `btoa('a')` retorna `'YQ=='`, e `atob('SA==')` retorna `'S'`.

O que [btoa()](https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa) realmente faz é tratar sua string como uma "string binária", uma string onde cada caractere representa exatamente um byte de dados binários, e então codifica esses bytes em Base64\. O caso de uso da MDN é para dados que causam problemas de transmissão, como caracteres de controle ASCII (0–31), que você deseja transportar por um canal apenas de texto.

Essa linha única é suficiente quando seu texto é ASCII: o ponto de código de cada caractere deve ser inferior a 256, e, conforme a MDN, a correspondência byte-ponto de código só é confiável até 0x7F. O intervalo 0x80–0xFF funciona tecnicamente, mas depende do comportamento de codificação Latin-1 que não é portátil entre ambientes. Uma boa regra: qualquer coisa não ASCII precisa do caminho UTF-8 abaixo.

## Por que btoa() gera InvalidCharacterError em emojis, acentos e CJK

Base64 é uma codificação binária, não uma codificação de texto. O [glossário da MDN](https://developer.mozilla.org/en-US/docs/Glossary/Base64) chama o hábito de passar texto arbitrário ou HTML para `btoa()` de um equívoco comum: `btoa`/`atob` antecedem arrays tipados, então usam strings para representar bytes. O problema começa quando sua string não tem um byte por caractere.

Strings JavaScript são UTF-16, então uma unidade de código tem sempre dois bytes, e caracteres fora do BMP (como emojis) ocupam quatro bytes como par substituto; UTF-8 usa de um a quatro bytes por ponto de código. `btoa()` e `atob()` funcionam apenas com caracteres de byte único (intervalo Latin-1). Tente codificar algo mais largo e você obterá este erro exato:

```
DOMException: Failed to execute 'btoa' on 'Window':
The string to be encoded contains characters outside of the Latin1 range

```

O caso problemático é trivial de reproduzir: `btoa('✓')` gera erro, e `btoa('a Ā 𐀀 文 🦄')` também. Emojis, letras acentuadas além do Latin-1 e caracteres CJK estão todos acima de 0xFF, então nenhum deles se encaixa na suposição de um byte por caractere. `'✓'` é U+2713, bem acima de 0xFF, então `btoa()` recusa em vez de corromper seus dados silenciosamente. Essa recusa é talvez o melhor recurso da API: ela falha abertamente em vez de produzir mojibake que você descobriria semanas depois.

Mais uma coisa vale saber antes de corrigir isso: Base64 aumenta o tamanho dos dados, em cerca de 33% comparado aos bytes brutos. Isso é aceitável para strings curtas, tokens e URIs de dados, mas é um motivo real para não codificar Base64 grandes payloads — codifique na fronteira necessária, não em todos os lugares.

![Um laço azul suave em 3D fluindo pela esquerda e dividindo-se em dois caminhos: uma das mechas forma grupos agrupados ordenados de…](https://www.tool-cloud.com/blog/pt/content/images/2026/10/javascript-base64-encode-utf8-split.webp)

Um fluxo de dados, duas pegadas de bytes: clusters multi-byte versus bytes únicos.

### O caso de borda do substituto solitário (e String.isWellFormed())

A maioria dos artigos pula isso, mas causa dores de cabeça: uma string UTF-16 contendo um substituto solitário (metade de um par de emoji, geralmente devido a um bug de fatiamento) é "malformada". Conforme o [guia do web.dev](https://web.dev/articles/base64-encoding), `TextDecoder` substitui silenciosamente U+FFFD por padrão. Antes de codificar, verifique a conformidade com `String.prototype.isWellFormed()`, ou capture o `URIError` que `encodeURIComponent()` gera em substitutos solitários, então decida explicitamente: rejeitar os dados, permitir a substituição deliberadamente ou gerar erro para análise posterior.

## O jeito correto: TextEncoder → bytes UTF-8 → Base64

A solução correta é converter sua string para bytes UTF-8 com `TextEncoder` primeiro, e então codificar os bytes em Base64 em vez da string. `new TextEncoder().encode(str)` transforma qualquer string JavaScript em uma `Uint8Array` de bytes UTF-8 (TextEncoder só fala UTF-8). No caminho de volta, `new TextDecoder()` assume UTF-8 por padrão e reverte exatamente. Observe o que `atob()` oferece aqui: uma string binária, um caractere por byte, não texto UTF-8\. É por isso que o lado da decodificação precisa de `TextDecoder` para transformar bytes de volta em texto legível.

### Auxiliares bytesToBase64() e base64ToBytes() (código pronto para copiar e colar)

Aqui está [o ciclo canônico da MDN](https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa), que roda em todos os navegadores que suportam `TextEncoder` (IE excluído):

```js
function bytesToBase64(bytes) {
  const binString = Array.from(bytes, (b) => String.fromCodePoint(b)).join('');
  return btoa(binString);
}

function base64ToBytes(base64) {
  const binString = atob(base64);
  return Uint8Array.from(binString, (m) => m.codePointAt(0));
}

```

### Verifique com um ciclo completo

Codificar uma string torna-se uma linha:

```js
const encoded = bytesToBase64(new TextEncoder().encode('a Ā 𐀀 文 🦄'));
// 'YSDEgCDwkICAIOaWhyDwn6aE'

```

Decodificar inverte o processo:

```js
const decoded = new TextDecoder().decode(base64ToBytes(encoded));
// 'a Ā 𐀀 文 🦄'

```

O ciclo verificado do web.dev confirma o mesmo padrão: `'hello⛳❤️🧀'` codifica para `'aGVsbG/im7PinaTvuI/wn6eA'` e decodifica de volta exatamente, inclusive emojis.

### Ignore o truque unescape(encodeURIComponent())

Você encontrará `btoa(unescape(encodeURIComponent(str)))` copiado em todos os lugares. Funciona, mas `unescape()` é legado do Anexo B, obsoleto desde o ECMAScript 3\. Código novo deve usar `TextEncoder` em vez disso: é explícito, padrão e não depende de um global obsoleto.

## O jeito de 2025: Uint8Array.toBase64() e Uint8Array.fromBase64()

Desde setembro de 2025, JavaScript tem métodos nativos de Base64 em `Uint8Array` próprios, então os auxiliares de string de bytes acima já não são a única opção. A [proposta Base64 do TC39](https://github.com/tc39/proposal-arraybuffer-base64/blob/main/README.md) atingiu o Estágio 4 e faz parte da linguagem; a justificativa do TC39 é que base64 não é uma codificação de texto, então TextEncoder/TextDecoder são conceitualmente a ferramenta errada para isso.

De acordo com a [MDN](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global%5FObjects/Uint8Array/toBase64), estas são funções da categoria "Disponíveis recentemente" nos navegadores modernos. Verifique os ambientes de execução antes de lançar: se você precisa suportar navegadores antigos ou versões antigas do Node, mantenha o fallback com `TextEncoder` \+ `btoa`. A MDN recomenda esses métodos em vez de `btoa()`/`atob()` quando você já possui um `Uint8Array`, pois evita a criação de strings brutas de bytes.

### Codificação: bytes.toBase64()

```js
const b64 = new TextEncoder().encode('Hello, world!').toBase64();
// 'SGVsbG8sIHdvcmxkIQ=='

```

Uma conversão UTF-8, uma chamada de método e pronto.

### Decodificação: Uint8Array.fromBase64()

```js
const text = new TextDecoder().decode(Uint8Array.fromBase64(b64));
// 'Hello, world!'

```

A MDN observa que `fromBase64()` deve ser preferido sobre `atob()` porque retorna um array de bytes real, a menos que os dados decodificados se destinem a ser texto ASCII. Ele aceita apenas o alfabeto base64 (A–Z, a–z, 0–9, além de `+/` ou `-_`), o preenchimento `=` opcional e ignora espaços em branco ASCII; ele lança `SyntaxError` ao encontrar caracteres fora do alfabeto.

### Opções: alphabet, omitPadding, lastChunkHandling

O [pacote de opções da especificação](https://tc39.es/proposal-arraybuffer-base64/) oferece controle preciso:

| Opção             | Valores                                           | O que faz                                                                             |
| ----------------- | ------------------------------------------------- | ------------------------------------------------------------------------------------- |
| alphabet          | 'base64' (padrão), 'base64url'                    | +// vs \-/\_                                                                          |
| omitPadding       | booleano                                          | Remove o \= final: new Uint8Array(\[72\]).toBase64() → 'SA==', com omitPadding → 'SA' |
| lastChunkHandling | 'loose' (padrão), 'strict', 'stop-before-partial' | Tolerância do decodificador para o último bloco                                       |

`'loose'` tolera falta de preenchimento e espaços em branco. `'strict'` exige blocos exatos de 4 caracteres com bits de estouro zerados, o que é ideal ao validar entradas não confiáveis. `'stop-before-partial'` é usado para streaming. O modo padrão flexível também tolera bits de estouro não nulos, que o modo estrito rejeita.

## Base64 vs base64url: qual alfabeto você precisa?

O base64 padrão usa `+` e `/` mais o preenchimento `=`, sendo adequado para `data:` URLs, pois essas não possuem segmentos de caminho ou strings de consulta. O base64url (RFC 4648 §5) substitui por `-` e `_` e geralmente omite o preenchimento, sendo obrigatório sempre que a saída viaja dentro de uma URL: JWTs usam base64url para seus três segmentos, por exemplo.

### Quando usar base64url

Use base64url quando a string codificada fizer parte de um caminho de URL ou parâmetro de consulta, onde `+` e `/` precisariam de escape (e o preenchimento `=` polui as strings de consulta). Use o base64 padrão para data URIs, incorporação de bytes em payloads JSON ou qualquer coisa que não seja uma URL.

### Como gerar base64url

Três maneiras, dependendo do ambiente:

- Navegadores modernos: `bytes.toBase64({ alphabet: 'base64url' })`
- Node 16+: `Buffer.from(str).toString('base64url')`
- Pós-processamento: pegue a saída padrão e substitua `+` → `-`, `/` → `_`, depois remova o `=`

Um detalhe importante: a RFC 4648 exige que os codificadores zerem os bits de estouro não utilizados no último bloco, e os decodificadores estritos podem lançar erro se eles não estiverem zerados. O glossário da MDN dá o exemplo de `'VR=='`, que é o mesmo byte que `'VQ=='` mas com bits de preenchimento sujos. Gere base64 com um codificador bem comportado e isso nunca acontecerá; se criar um manualmente, pode acontecer.

## Codificar um arquivo ou imagem para Base64 (data URLs)

Para arquivos, a rota no navegador é `FileReader` com `readAsDataURL()`, que gera uma data URL completa, e então você remove o prefixo para obter o base64 puro. Para imagens já renderizadas em um canvas, `toDataURL('image/png')` faz isso em uma única chamada.

### FileReader.readAsDataURL() → data URL → base64 puro

```js
function fileToDataURL(file) {
  return new Promise((resolve) => {
    const reader = new FileReader();
    reader.onload = () => resolve(reader.result);
    reader.readAsDataURL(file);
  });
}

const dataUrl = await fileToDataURL(fileInput.files[0]);
const rawBase64 = dataUrl.replace(/^data:\w+\/\w+;base64,/, '');

```

### canvas.toDataURL() para imagens

Se você desenhou uma imagem em um canvas (redimensionar, recortar, etc.), ignore o FileReader completamente:

```js
const dataUrl = canvas.toDataURL('image/png');

```

A mesma remoção de prefixo se aplica se você precisar apenas da string base64 crua.

### Data URL de volta para bytes

O sentido inverso é um fetch e um array buffer. O exemplo da MDN: uma data URL construída a partir de `new Uint8Array([0,1,2])` é `'data:application/octet-stream;base64,AAEC'`, e você recupera os bytes assim:

```js
const res = await fetch(dataUrl);
const bytes = new Uint8Array(await res.arrayBuffer());
// [0, 1, 2]

```

E o lembrete pelo qual este artigo inteiro existe: não chame `btoa()` em texto ou HTML arbitrários para construir data URLs. É um codificador byte a byte, e entradas não Latin-1 causarão erro.

## Node.js: Buffer.from(str, 'base64') — e a sua única diferença perigosa

O Node tem suas próprias soluções idiomáticas que dispensam a dança do TextEncoder: `Buffer.from('Hello, world! 🌍').toString('base64')` lida com Unicode automaticamente, pois o Buffer trabalha com bytes desde o início. Decodifique com `Buffer.from(encoded, 'base64').toString('utf8')`.

Outras formas úteis: `Buffer.from(str).toString('base64url')` (Node 16+), e arquivos inteiros via `fs.readFileSync('image.png').toString('base64')`.

```js
const encoded = Buffer.from('Hello, world! 🌍').toString('base64');
const decoded = Buffer.from(encoded, 'base64').toString('utf8');

```

### O Node não valida seu base64 (falhas silenciosas)

Aqui está a parte que surpreende as pessoas: o decodificador base64 do Node não valida a entrada. `Buffer.from('!!!!', 'base64').toString()` retorna `''` sem erro, e `Buffer.from('aGVsbG8!!!', 'base64')` descarta silenciosamente o lixo e retorna `'hello'`. Compare isso com `atob('aGVsbG8!!!')`, que lança `InvalidCharacterError`. Se o base64 vier de usuários, uma API ou terceiros, valide-o antes de decodificar no Node, ou use `Uint8Array.fromBase64()` com `lastChunkHandling: 'strict'` onde os ambientes de execução suportarem.

### btoa/atob estão obsoletos? Navegadores vs Node

Isso é realmente contraditório, então aqui vai uma resolução honesta. Nos navegadores, a [MDN marca btoa() e atob()](https://developer.mozilla.org/en-US/docs/Web/API/Window/btoa) como Baseline amplamente disponível desde julho de 2015, ou seja, não obsoletas. No Node, as [definições de tipo](https://github.com/DefinitelyTyped/DefinitelyTyped/discussions/58795) as marcam como `@deprecated` com o comentário de que "nunca devem ser usadas em código novo", recomendando `Buffer.from(str, 'base64')` em vez disso.

Uma boa regra: é uma API legada, não removida. Aceitável no código do navegador, mas prefira `Buffer` em código específico do Node. Por consenso da comunidade (não uma garantia da especificação), `btoa`/`atob` também são a escolha prática multiambiente se você precisar de um único caminho de código que rode inalterado em navegadores, Deno e Node sem dependências.

## O que realmente usar

Se você levar apenas uma recomendação deste artigo, são as três linhas abaixo. Mantenha `btoa`/`atob` para ASCII puro e bases de código legadas, e use o helper `bytesToBase64` como fallback do navegador até que `toBase64()` cubra todo o seu público.

```js
// Modern browsers (2025+)
const enc = new TextEncoder().encode(str).toBase64();
const dec = new TextDecoder().decode(Uint8Array.fromBase64(b64));

// Browser fallback (MDN helper)
const encFallback = bytesToBase64(new TextEncoder().encode(str));

// Node (validate input first if it isn't yours)
const encNode = Buffer.from(str).toString('base64');

```

Antes de lançar, verifique sua saída com uma rápida ida e volta em uma ferramenta de navegador. Cole `'Hello, world!'` no [Codificador / Decodificador Base64 gratuito da Tool Cloud](https://www.tool-cloud.com/pt/dev/base64%5Fencoder/), confirme que você obtém `'SGVsbG8sIHdvcmxkIQ=='`, depois decodifique de volta e verifique se é idêntico. Há também um [conversor de Texto para Base64](https://www.tool-cloud.com/pt/general/text%5Fto%5Fbase64/) e um [conversor de Base64 para Texto](https://www.tool-cloud.com/pt/general/base64%5Fto%5Ftext/) independentes; os arquivos são excluídos automaticamente e nada precisa ser instalado.

## Perguntas frequentes

### Por que btoa() falha com emojis, mas funciona com texto em inglês?

btoa() trata cada caractere como um único byte e exige que cada ponto de código seja inferior a 256 (de forma confiável, apenas até 0x7F). Emojis, caracteres acentuados e textos em CJK precisam de múltiplos bytes, então eles acionam um DOMException: InvalidCharacterError. Converta para bytes UTF-8 usando TextEncoder primeiro, depois codifique os bytes.

### btoa() está obsoleto?

Não nos navegadores — a MDN marca btoa() e atob() como amplamente disponíveis desde julho de 2015\. No entanto, as definições de tipo do Node as marcam como obsoletas em favor de Buffer.from(str, 'base64') em código específico do Node. Elas são APIs legado, não removidas.

### Como codificar Base64 texto Unicode (acentos, chinês, emoji)?

Use new TextEncoder().encode(str) para obter bytes UTF-8, depois codifique os bytes (btoa() via um auxiliar de string de bytes, ou Uint8Array.toBase64() em navegadores modernos). Para decodificar, use Uint8Array.fromBase64() ou atob() para recuperar os bytes, depois new TextDecoder().decode(bytes).

### Qual a diferença entre base64 e base64url?

base64url (RFC 4648 §5) usa '-' e '\_' em vez de '+' e '/', e geralmente omite o preenchimento '='. Use base64url quando a saída for inserida em URLs ou JWTs; o base64 padrão é adequado para data: URLs, que não possuem segmentos de caminho ou strings de consulta.

### Por que o Node.js não gera erro em Base64 inválido?

O Buffer.from(str, 'base64') do Node não valida a entrada: ele ignora silenciosamente caracteres inválidos, então Buffer.from('aGVsbG8!!!', 'base64').toString() retorna 'hello' sem erro. Nos navegadores, atob() gera InvalidCharacterError na mesma entrada. Valide Base64 não confiável antes de decodificar no Node.