---
title: Copying The Current Safari Tab as a Clickable Link
description: In this post, I outline how to quickly copy the URL and title of the active Safari tab as a clickable link, a convenient feature for referencing web pages in emails, to-do lists, documentation, and messaging platforms like Slack.
date: 2023-11-11
url: https://aaron.cc/copying-the-current-safari-tab-as-a-to-the-clipboard-as-a-clickable-link/
---


After switching from Chrome to Safari, I started missing the excellent [TabCopy](https://chromewebstore.google.com/detail/tabcopy/micdllihgoppmejpecmkilggmaagfdmb?pli=1) extension that allowed me to easily copy the current tab’s URL to the clipboard, formatted as a clickable link displaying the page title. I often use this to reference web pages in emails, to-do lists, documentation, Slack, etc. Instead of dealing with potentially long URLs, I prefer pasting a human-readable link with the URL hidden behind it.

This post outlines how I managed to implement this specific requirement for Safari. I’m not focussing on TabCopy’s other features as they weren’t relevant for my workflow.

**TL;DR:** Here’s the finished script which retrieves the URL and title of the active Safari tab, constructs an HTML link, and copies it to the macOS clipboard. It also includes a plain-text representation in Markdown syntax.

You can use an automation tool such as [Alfred](https://www.alfredapp.com) to bind this script to a hot key local to Safari and show a notification when done:

{{< img

  src="images/Alfred-Workflow.png"
  caption="Alfred Workflow to bind the script to a hot key and show a notification."
>}}

## The Script Explained

### Fetching the Title

Using AppleScript, we fetch the URL and the title displayed in the frontmost Safari window.

### Massaging the Title

Starting with version 17, Safari introduced support for profiles. The profile name will be prefixed to the document title that is retrieved using AppleScript. We detect it based on the long dash (—), which Safari uses to separate the profile name from the web page title, and strip that string using `sed`.

You can extend this function to do further processing if needed.

### Preparing The HTML String

Adding the `<meta charset='utf-8'>` ensures that the string is treated as UTF-8 when adding it to the clipboard. Without this, special characters in the page title *will* break.

I’m also adding a style tag to use the default sans-serif font when pasting the link, which I usually prefer. Your mileage may vary.

`hexdump -ve '1/1 "%.2x"'` will convert a string into a stream of two-digit hexadecimal numbers, without skipping any repeated lines. This seems to be required to get the string over into the AppleScript world, which I learned in [this StackOverflow](https://stackoverflow.com/a/11089226/1387396) post.

### Preparing a Plain Text Version

Some apps, such as Slack, are picky and won’t paste the HTML string when no plain text version is present (details in the next section below). I’m therefore adding plain text representation in Markdown syntax which includes both the page title and the link.

### Setting the Clipboard

Finally, I’m writing both strings to the clipboard, again using AppleScript.

## Getting It To Work In Slack

At first glance, all seemed to work, as the link would paste correctly in native macOS apps, such as Mail, TextEdit, or OmniOutliner. However, at some point I noticed that it wasn’t working in Slack. Performing the paste action would do nothing, not even giving me the title without the link. Maybe this is an issue with Electron apps in general, which I haven’t verified.

I was puzzled and decided to take a deep dive into the inner workings of the macOS clipboard. I knew that copying a link from a webpage in Chrome or Safari and pasting it into Slack worked correctly, so I wanted to figure out how the raw data would look differently in the clipboard.

Apple provides a Clipboard Viewer utility as part of the [Additional Tools for Xcode](https://developer.apple.com/download/all/?q=additional%20tools%20for%20xcode), which was exactly what I needed to get to the bottom of this. Despite having an icon that you’d never expect from an Apple app shipped today, it gets its job done, no frills.

{{< img

  src="images/Clipboard-Viewer-Icon.jpg"
  alt="A collection of three application icons. From left to right: The first icon shows a chessboard with a knight piece, representing Apple’s chess application. The second icon features a golden lamp with smoke trailing from its spout, signifying Apple’s Clipboard Viewer application. The third icon displays a simple clock face with hands indicating ten past ten, symbolizing Apple’s clock application."
>}}

Manually copying a link from a web page in Safari would write the following data in the clipboard:

{{< img

  src="images/Manually-Copied-From-Safari--HTML-.png"
  alt="Clipboard Viewer with public.html data type selected and many other data types available."
>}}

More than I expected. There are multiple HTML and RTF representations, including a *com.apple.webarchive* data type, and various plain text representations in both UTF-8 and UTF-16.

In contrast, my script would only write two data types, both being the HTML representation:

{{< img

  src="images/Copied-Using-My-Script--HTML-only--1.png"
  alt="Clipboard Viewer showing public.html and Apple HTML pasteboard type, containing a link to the Nyan Cat Wikipedia page."
>}}

After some trial and error, I found out that the plain text version is key. Slack expects a plain text to be included, even though it won’t be using it at all. As long as a plain text is included, it will happily paste the HTML version.

So I updated my script to include the plain text version:

```
plain=$(echo "[${title}](${url})" | sed 's/"/\\"/g')
osascript <<EOF
set the clipboard to {«class HTML»:«data HTML${html}», string:"${plain}"}
EOF
```

For some reason, this adds a bunch of other plain text representations. But it does the trick! The link can now be pasted into Slack.

{{< img

  src="images/Copied-Using-My-Script--Plain-Text-.png"
>}}

To make this more useful, I decided to use the Markdown syntax here.

## Credits

- Header artwork generated with ChatGPT and DALL·E.
- <https://stackoverflow.com/a/11089226/1387396>
