Overview
What Extract URLs does
Finds HTTP, HTTPS, www-style, and protocol-free domain links, removes surrounding sentence punctuation, ignores domains inside email addresses, preserves balanced URL brackets, and returns one unique URL per line.
| Category | Extraction |
|---|---|
| Action type | JavaScript |
| Default result | Copy the result |
| Internet | Not required |
Example
Action and outcome
| Action | Outcome |
|---|---|
| Extract URLsSelected text: See example.com/docs, then https://actionclip.app. | example.com/docs https://actionclip.app |
Workflow
Use Extract URLs
Follow these steps to extract unique web URLs from selected text with ActionClip.
- Select the text you want to use.
- Choose Extract URLs from ActionClip.
- Review the extracted result, then copy it where you need it.
Before you add it
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.
Inspect before installing
Action script
The script below is included so you can inspect how the action works before downloading it.
JavaScript definition
function run(selected_text) {
const domainLabel = "(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?)";
const topLevelDomain = "(?:[a-z]{2,63}|xn--[a-z0-9-]{2,59})";
const bareDomain = "(?:" + domainLabel + "\\.)+" + topLevelDomain;
const explicitURL = "(?:https?:\\/\\/|www\\.)[^\\s<>\\\"']+";
const domainURL = bareDomain
+ "(?::\\d{2,5})?"
+ "(?:\\/[^\\s<>\\\"']*)?"
+ "(?:\\?[^\\s<>\\\"']*)?"
+ "(?:#[^\\s<>\\\"']*)?";
const pattern = new RegExp("\\b(?:" + explicitURL + "|" + domainURL + ")", "gi");
const matches = Array.from(selected_text.matchAll(pattern))
.filter((match) => match.index === 0 || selected_text[match.index - 1] !== "@")
.map((match) => match[0]);
function trimTrailingPunctuation(value) {
let result = value.replace(/[.,;:!?]+$/g, "");
const pairs = [["(", ")"], ["[", "]"], ["{", "}"]];
pairs.forEach(([opening, closing]) => {
while (result.endsWith(closing)) {
const opens = result.split(opening).length - 1;
const closes = result.split(closing).length - 1;
if (closes <= opens) break;
result = result.slice(0, -1);
}
});
return result;
}
const seen = new Set();
const urls = [];
matches.map(trimTrailingPunctuation).forEach((url) => {
if (!seen.has(url)) {
seen.add(url);
urls.push(url);
}
});
return urls.length ? urls.join("\n") : "No URLs found.";
}