Developer Tools

Base64 Decode

Decode Base64 into validated UTF-8 text.

OfficialOn-device

Download action

What Base64 Decode does

Accepts padded or unpadded standard and URL-safe Base64, ignores whitespace, and rejects malformed Base64 or invalid UTF-8 bytes.

CategoryDeveloper Tools
Action typeJavaScript
ResultReplace or copy text
InternetNot required

Action and outcome

Base64 Decode example
ActionOutcome
Base64 DecodeSelected text: QWN0aW9uQ2xpcA==ActionClip

Use Base64 Decode

Follow these steps to decode Base64 into validated UTF-8 text with ActionClip.

  1. Select the text you want to use.
  2. Choose Base64 Decode from ActionClip.
  3. Review the result, then replace the selection or copy the new text.

Requirements and privacy

  • Before you start: No setup required.
  • Your selected text: Runs locally in ActionClip’s JavaScript sandbox. Selected text does not leave your Mac.

Action configuration

The definition below is included so you can inspect how the action works before downloading it.

JavaScript definition
function run(selected_text) {
  const alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  let input = selected_text.replace(/\s+/g, "").replace(/-/g, "+").replace(/_/g, "/");
  if (!/^[A-Za-z0-9+/]*={0,2}$/.test(input) || input.length % 4 === 1) {
    throw new Error("Invalid Base64 text.");
  }
  input = input.replace(/=+$/, "");
  while (input.length % 4 !== 0) input += "=";

  const bytes = [];
  for (let index = 0; index < input.length; index += 4) {
    const a = alphabet.indexOf(input[index]);
    const b = alphabet.indexOf(input[index + 1]);
    const c = input[index + 2] === "=" ? 0 : alphabet.indexOf(input[index + 2]);
    const d = input[index + 3] === "=" ? 0 : alphabet.indexOf(input[index + 3]);
    if (a < 0 || b < 0 || c < 0 || d < 0) throw new Error("Invalid Base64 text.");
    const value = (a << 18) | (b << 12) | (c << 6) | d;
    bytes.push((value >> 16) & 255);
    if (input[index + 2] !== "=") bytes.push((value >> 8) & 255);
    if (input[index + 3] !== "=") bytes.push(value & 255);
  }

  let output = "";
  for (let index = 0; index < bytes.length;) {
    const first = bytes[index++];
    let codePoint;
    if (first <= 0x7F) {
      codePoint = first;
    } else if (first >= 0xC2 && first <= 0xDF) {
      if (index >= bytes.length || (bytes[index] & 0xC0) !== 0x80) throw new Error("Decoded bytes are not valid UTF-8.");
      codePoint = ((first & 0x1F) << 6) | (bytes[index++] & 0x3F);
    } else if (first >= 0xE0 && first <= 0xEF) {
      if (index + 1 >= bytes.length || (bytes[index] & 0xC0) !== 0x80 || (bytes[index + 1] & 0xC0) !== 0x80) {
        throw new Error("Decoded bytes are not valid UTF-8.");
      }
      const second = bytes[index++];
      const third = bytes[index++];
      if ((first === 0xE0 && second < 0xA0) || (first === 0xED && second >= 0xA0)) {
        throw new Error("Decoded bytes are not valid UTF-8.");
      }
      codePoint = ((first & 0x0F) << 12) | ((second & 0x3F) << 6) | (third & 0x3F);
    } else if (first >= 0xF0 && first <= 0xF4) {
      if (index + 2 >= bytes.length || (bytes[index] & 0xC0) !== 0x80
        || (bytes[index + 1] & 0xC0) !== 0x80 || (bytes[index + 2] & 0xC0) !== 0x80) {
        throw new Error("Decoded bytes are not valid UTF-8.");
      }
      const second = bytes[index++];
      const third = bytes[index++];
      const fourth = bytes[index++];
      if ((first === 0xF0 && second < 0x90) || (first === 0xF4 && second >= 0x90)) {
        throw new Error("Decoded bytes are not valid UTF-8.");
      }
      codePoint = ((first & 7) << 18) | ((second & 0x3F) << 12)
        | ((third & 0x3F) << 6) | (fourth & 0x3F);
    } else {
      throw new Error("Decoded bytes are not valid UTF-8.");
    }
    output += String.fromCodePoint(codePoint);
  }
  return output;
}