Атрибут ping заставляет браузер сообщить серверу о клике по ссылке. Пока читатель переходит по адресу из href, браузер отдельно отправляет короткий запрос на адреса, которые вы записали в ping. Его пишут в теге <a> и в теге <area> . Ниже разобрано, что именно уходит на сервер, как принять этот сигнал, почему на него нельзя полагаться как на единственный счётчик и чем он отличается от обычной аналитики.
<a href="/files/price.pdf" ping="/stat/click">Скачать прайс</a>
В этой статье
- Атрибут ping в HTML: что делает и у каких тегов работает
- Значение атрибута ping: как записать один адрес или несколько
- Что отправляет атрибут ping: запрос, заголовки и тело
- Атрибут ping и счётчик кликов: как принять сигнал на сервере
- Атрибут ping и браузеры: где он работает, а где выключен
- Атрибут ping и приватность: чем он отличается от аналитики
- Как прочитать и изменить атрибут ping через JavaScript
- Частые ошибки с атрибутом ping
- Шпаргалка по атрибуту ping
Атрибут ping в HTML: что делает и у каких тегов работает
Обычно клик по ссылке видит только следующая страница. Чтобы посчитать клики по ссылкам на чужие сайты или на файлы, раньше ставили на ссылку скрипт или гнали переход через промежуточный адрес. Атрибут ping решает это одной записью в разметке: браузер сам отправит сигнал, а переход пойдёт как обычно. Не путайте с командой ping из Windows, которая проверяет связь с сервером: у атрибута другая задача.
| Тег | Что делает ping | Пример записи |
|---|---|---|
<a> | При клике по ссылке отправляет сигнал на указанные адреса | <a href="/price.pdf" ping="/stat/click"> |
<area> | То же для области на карте-изображении | <area href="/price.pdf" ping="/stat/click" alt="Прайс"> |
<link> , <button> , <form> | Не поддерживают: такого атрибута у них нет | <button ping="/stat"> ничего не сделает |
Правила записи и поведения описаны в разделе стандарта HTML про отслеживание переходов по ссылкам .
Значение атрибута ping: как записать один адрес или несколько
Значение ping это список адресов через пробел. Адрес может быть относительным, как у href, или полным, и вести даже на другой сайт. Годятся адреса http и https, а ftp, data, blob и javascript браузер пропускает. Пустое значение ничего не отправляет. Если адресов несколько, запрос уйдёт на каждый.
| Запись | Что произойдёт при клике | Пример записи |
|---|---|---|
| Один адрес | Один запрос на этот адрес | ping="/stat/click" |
| Несколько адресов | По запросу на каждый адрес из списка | ping="/stat/a /stat/b" |
| Адрес другого сайта | Запрос уйдёт и туда, поэтому следите, кому доверяете | ping="https://stat.example.com/c" |
| Пустое значение | Запросов нет | ping="" |
Адреса разделяет только пробел. Запятая и точка с запятой разделителями не считаются, поэтому запись через запятую даст один неправильный адрес.
<a href="/dest" ping="/ping-a /ping-b /ping-c">...</a>
Пример: сколько запросов уходит при клике
Нажмите каждую ссылку и посмотрите в списке, какие запросы ушли. Страница читает их через браузер, поэтому в списке то, что браузер отправил на самом деле.
Что отправляет атрибут ping: запрос, заголовки и тело
Сигнал это обычный POST-запрос. Браузер отправляет его во время перехода по ссылке и не показывает читателю ничего: ни ошибок, ни загрузки. Тело запроса всегда одно и то же, слово PING, а полезная информация лежит в заголовках.
POST /stat/click HTTP/1.1
Content-Type: text/ping
Ping-From: https://site.ru/catalog.html
Ping-To: https://site.ru/files/price.pdf
PING
| Что в запросе | Что это значит | Пример записи |
|---|---|---|
Ping-From | Страница, на которой нажали ссылку | https://site.ru/catalog.html |
Ping-To | Адрес, куда ведёт ссылка (из href) | https://site.ru/files/price.pdf |
Content-Type | Тип тела запроса, обычно text/ping | text/ping |
| Тело | Слово PING и больше ничего | PING |
Набор заголовков может отличаться от браузера к браузеру, поэтому надёжно использовать лишь то, что в запросе есть всегда: сам адрес, на который пришёл POST. Нужные сведения удобно передавать прямо в адресе ping, например номер товара: ping="/stat/click?id=17".
Атрибут ping и счётчик кликов: как принять сигнал на сервере
Принять сигнал может любой сервер, который умеет отвечать на POST. Ответ браузер не читает, поэтому достаточно коротко ответить кодом 204 «без содержимого». Вот минимальный пример на Node.js: он считает клики и записывает адрес, куда вела ссылка.
const http = require("http");
let clicks = 0;
http.createServer((req, res) => {
if (req.method === "POST" && req.url === "/stat/click") {
clicks++;
console.log(clicks, req.headers["ping-to"]);
res.writeHead(204);
return res.end();
}
res.writeHead(404);
res.end();
}).listen(3000);
Без своего сервера атрибут бесполезен: сигнал можно отправить, но принимать его некому. На сайте, где нельзя запускать серверный код, например на Blogger, ping принесёт пользу только вместе с адресом внешней службы, которой вы доверяете.
Атрибут ping и браузеры: где он работает, а где выключен
Атрибут описан в стандарте, но его отправка зависит от браузера и его настроек. Сигнал уходит не всегда, и главные причины такие.
| Ситуация | Что происходит | Пример записи |
|---|---|---|
| Обычный браузер на компьютере | Сигнал обычно уходит при клике | ping="/stat/click" |
| Отправка выключена настройкой | Запроса нет, а переход работает. В некоторых браузерах за это отвечает настройка, например browser.send_pings | about:config |
| Расширение блокировщика | Блокировщики рекламы и приватности могут резать такие запросы | ping="/stat/click" |
Ссылка без href | Клика-ссылки нет, значит, и сигнала нет | <a ping="/stat"> |
Поэтому счётчик на ping всегда занижает число кликов. Для точных цифр его сверяют с серверными журналами или другой аналитикой. Актуальную таблицу поддержки смотрите на странице тега a в MDN или на Can I use.
Пример: в каких случаях при клике уходит сигнал
Нажимайте ссылки и кнопку: список покажет, на каких действиях браузер отправил запрос. Ссылка без href не считается ссылкой, и сигнала от неё не будет.
Сигнал уходит при обычном клике, при открытии в новой вкладке, при скачивании файла и при клике через скрипт link.click(). Этого достаточно, чтобы считать клики по ссылкам на файлы, которые вы раздаёте со своего сайта.
Атрибут ping и приватность: чем он отличается от аналитики
Читатель не видит, что клик отправил сигнал: ни подсказки, ни значка. Поэтому у ping репутация скрытого слежения, и часть блокировщиков отрезает его по умолчанию. Если вы используете атрибут, упомяните сбор статистики на странице о конфиденциальности. Это общее правило, а не юридическая консультация.
| Способ | Чем отличается | Пример записи |
|---|---|---|
ping | Работает без скрипта, но читатель не может его отключить на странице | <a ping="/stat"> |
fetch в обработчике клика | Нужен скрипт, зато виден в коде и гибче в настройках | link.addEventListener("click", ...) |
navigator.sendBeacon | Скрипт отправляет запрос так, чтобы он не потерялся при уходе со страницы | navigator.sendBeacon("/stat") |
| Обычная аналитика | Считает посещения страниц, а не клики по отдельной ссылке | Метрика, GA |
Если нужен точный счётчик с гибкой логикой, используйте скрипт. Если нужна лёгкая запись клика на файл или внешнюю ссылку без скрипта, ping подойдёт, пока вы принимаете, что часть кликов потеряется.
Как прочитать и изменить атрибут ping через JavaScript
В JavaScript у ссылки есть свойство ping, строка со списком адресов, как в атрибуте. Если атрибута нет, возвращается пустая строка. Записать новое значение можно присваиванием, а список адресов проще всего разбирать через split.
const link = document.querySelector("a");
link.ping; // "" если атрибута нет
link.hasAttribute("ping"); // true или false
link.ping = "/stat/a /stat/b"; // два адреса
link.ping.split(" "); // ["/stat/a", "/stat/b"]
link.removeAttribute("ping");
Пример: чтение и запись свойства ping
Нажимайте кнопки: таблица показывает свойство, наличие атрибута и число адресов. «Нажать на ссылку» отправляет сигнал на все адреса, которые сейчас записаны, а без атрибута сигнала нет.
Частые ошибки с атрибутом ping
Почти все проблемы с ping сводятся к ожиданию, что сигнал придёт всегда и в готовом виде. Он приходит не всегда и очень скуп на сведения.
| Ошибка | Что происходит | Как исправить |
|---|---|---|
Считать клики только по ping | Часть сигналов теряется из-за настроек и блокировщиков | Сверять с серверными журналами или другой аналитикой |
Разделить адреса запятой: ping="/a,/b" | Получится один неправильный адрес | Разделять адреса пробелом |
Ждать, что ping заменит href | Переход идёт по href, а ping лишь сообщает о нём | Всегда писать оба атрибута |
<a ping> без href | Это не ссылка, клик сигнала не отправляет | Добавить href |
<button ping="/stat"> | У кнопки такого атрибута нет, ничего не уходит | Скрипт или ссылка с ping |
Принимать сигнал через GET | Сервер получит только POST, адрес вернёт ошибку | Обработать метод POST |
| Отвечать на сигнал длинной страницей | Ответ браузер всё равно не читает, зря тратится время сервера | Отвечать кодом 204 без содержимого |
| Прятать сбор статистики | Читатель не знает, что клики считаются | Написать об этом в политике конфиденциальности |
Шпаргалка по атрибуту ping
Всё главное об атрибуте ping в одной таблице.
| Что | Как работает | Пример записи |
|---|---|---|
| Где пишут | У a и area, при наличии href | <a href="/a" ping="/stat"> |
| Значение | Список адресов через пробел | ping="/stat/a /stat/b" |
| Запрос | POST с телом PING | Content-Type: text/ping |
| Заголовки | Откуда нажали и куда ведёт ссылка | Ping-From, Ping-To |
| Когда уходит | При обычном клике, в новой вкладке, при скачивании, при click() | link.click() |
| Ответ сервера | Браузер его не читает, хватит 204 | res.writeHead(204) |
| Надёжность | Сигнал может не дойти: настройки, блокировщики | browser.send_pings |
| JavaScript | link.ping это строка, пустая, пока атрибута нет | link.ping = "/stat" |