---
title: "Extract Phone Numbers action for ActionClip"
canonical_url: "https://actionclip.app/actions/extract-phone-numbers"
document_type: "standalone_action"
official: true
action_count: 1
catalog_schema_version: 1
catalog_revision: "2026-08-25.3"
catalog_published_at: "2026-08-25T10:06:27Z"
---

# Extract Phone Numbers action for ActionClip

Extract unique phone numbers from selected text.

## What it does

Finds common local and international phone-number formats with optional country codes and extensions, preserves readable formatting, removes equivalent duplicates, and filters obvious dates, IP addresses, postal codes, government-ID patterns, and malformed or overlong numbers.

## Action details

| Field | Value |
| --- | --- |
| Category | Extraction |
| Action type | JavaScript |
| Default result | Copy the result |
| Internet | Not required |

## Action and outcome

| Action | Outcome |
| --- | --- |
| **Extract Phone Numbers** — Selected text: Call +1 (415) 555-2671 or +44 20 7946 0958 ext. 42. | +1 (415) 555-2671 +44 20 7946 0958 ext. 42 |

## How to extract unique phone numbers from selected text with ActionClip

1. Select the text you want to use.
2. Choose **Extract Phone Numbers** from ActionClip.
3. Review the extracted result, then copy it where you need it.

## Requirements

No setup required.

## Privacy

Runs locally in ActionClip’s JavaScript sandbox. Selected text does not leave your Mac.

## Action script

````javascript
function run(selected_text) {
  const horizontalSpace = "[\\t \\u00A0\\u202F]";
  const candidatePattern = new RegExp(
    "(?:(?:\\+|00)" + horizontalSpace + "*(?:"
      + "\\(" + horizontalSpace + "*\\d{1,4}" + horizontalSpace + "*\\)|\\d)"
      + "|(?:\\(" + horizontalSpace + "*\\d{1,4}" + horizontalSpace + "*\\)|\\d))"
      + "[\\d\\t \\u00A0\\u202F().\\/-]{3,}\\d"
      + "(?:" + horizontalSpace + "*(?:(?:ext(?:ension)?)\\.?|x|#)"
      + horizontalSpace + "*\\d{1,6})?",
    "giu"
  );
  const extensionPattern = /[\t \u00A0\u202F]*(?:(?:ext(?:ension)?)\.?|x|#)[\t \u00A0\u202F]*(\d{1,6})$/iu;

  function hasSafeBoundaries(match) {
    const before = match.index > 0 ? selected_text[match.index - 1] : "";
    const afterIndex = match.index + match[0].length;
    const after = afterIndex < selected_text.length ? selected_text[afterIndex] : "";
    if ((before === "(") !== (after === ")")) return false;
    return !/[\p{L}\p{N}_]/u.test(before) && !/[\p{L}\p{N}_]/u.test(after);
  }

  function hasBalancedPhoneParentheses(value) {
    let depth = 0;
    for (const character of value) {
      if (character === "(") {
        depth += 1;
        if (depth > 1) return false;
      } else if (character === ")") {
        depth -= 1;
        if (depth < 0) return false;
      }
    }
    if (depth !== 0) return false;
    const withoutValidGroups = value.replace(/\([\t \u00A0\u202F]*\d{1,4}[\t \u00A0\u202F]*\)/g, "");
    return !/[()]/.test(withoutValidGroups);
  }

  function isObviousNonPhone(value) {
    const compact = value.replace(/[\t \u00A0\u202F]/g, "");
    if (/^(?:19|20)\d{2}[./-]\d{1,2}[./-]\d{1,2}$/.test(compact)) return true;
    if (/^\d{1,2}[./-]\d{1,2}[./-](?:19|20)\d{2}$/.test(compact)) return true;
    if (/^\d{3}-\d{2}-\d{4}$/.test(compact)) return true;
    if (/^\d{5}-\d{4}$/.test(compact)) return true;
    if (/^97[89](?:[-.]\d+){3,5}$/.test(compact)) return true;

    const ipv4 = compact.match(/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/);
    return Boolean(ipv4 && ipv4.slice(1).every((part) => Number(part) <= 255));
  }

  function parseCandidate(match) {
    if (!hasSafeBoundaries(match)) return null;

    const readable = match[0]
      .replace(/[\u00A0\u202F]/g, " ")
      .replace(/[\t ]+/g, " ")
      .trim();
    const extensionMatch = readable.match(extensionPattern);
    const extension = extensionMatch ? extensionMatch[1] : "";
    const core = extensionMatch
      ? readable.slice(0, extensionMatch.index).trim()
      : readable;

    if (!hasBalancedPhoneParentheses(core) || isObviousNonPhone(core)) return null;

    const digits = core.replace(/\D/g, "");
    const usesDialOutPrefix = /^00/.test(core.replace(/[\t ]/g, ""));
    const phoneDigits = usesDialOutPrefix ? digits.slice(2) : digits;
    if (phoneDigits.length < 7 || phoneDigits.length > 15) return null;
    if (/^(\d)\1+$/.test(phoneDigits)) return null;

    const groups = core
      .replace(/^\+/, "")
      .replace(/[()]/g, " ")
      .trim()
      .split(/[\t ./-]+/)
      .filter(Boolean);
    if (groups.length > 1 && groups.some((group) => group.length > 6)) return null;
    if (groups.length > 6) return null;

    const canonicalCore = usesDialOutPrefix
      ? "+" + phoneDigits
      : (core.trim().startsWith("+") ? "+" : "") + phoneDigits;
    return {
      value: readable,
      key: canonicalCore + (extension ? "x" + extension : "")
    };
  }

  const seen = new Set();
  const phoneNumbers = [];
  for (const match of selected_text.matchAll(candidatePattern)) {
    const parsed = parseCandidate(match);
    if (!parsed || seen.has(parsed.key)) continue;
    seen.add(parsed.key);
    phoneNumbers.push(parsed.value);
  }

  return phoneNumbers.length ? phoneNumbers.join("\n") : "No phone numbers found.";
}
````

## Links

- [HTML listing](https://actionclip.app/actions/extract-phone-numbers)
- [Download action definition](https://actionclip.app/actions/extract-phone-numbers.actionclip)
- [Browse Extraction actions](https://actionclip.app/marketplace#marketplace-extraction)
- [All Marketplace listings](https://actionclip.app/marketplace)
