虽然我们可以使用busuanzi简单的添加网站统计,但是由于已经添加了Umami 统计,那么就没必要再额外的使用busuanzi做一层计算了,而且Umami 的统计更全面可靠,那么我们如何获取umami的统计信息并添加到网站呢?
有两种方法。
- 第一种是调用官网API的方法,这一种为了避免Token泄露,需要添加一层中间代理,比如使用CloudFlare Worker或者EdgeOne page。
- 第二种是采用爬虫策略直接爬取Share链接的信息。
调用官网API的方法
需要注意,这种方法存在限制,官方API有速率限制,而中间层的边缘计算具有次数限制,小量使用完全没问题,但是大量的话会出问题。
云函数代理
我这里使用腾讯EdgeOne的Page Function作为中间层代理,创建目录./edge-functions/umami.js并写入:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| export async function onRequest(context) { const UMAMI_BASE = "https://api.umami.is/v1"; const WEBSITE_ID = context.env.UMAMI_WEBSITE_ID; const TOKEN = context.env.UMAMI_API_TOKEN;
const createdAt = "2025-12-30T17:21:06.019Z"; const start = new Date(createdAt).getTime(); const end = new Date().getTime();
let apiUrl = `${UMAMI_BASE}/websites/${WEBSITE_ID}/stats?startAt=${start}&endAt=${end}`;
try { const res = await fetch(apiUrl, { headers: { Authorization: `Bearer ${TOKEN}`, Accept: "application/json", }, });
if (!res.ok) { return new Response(JSON.stringify({ error: "Umami API error" }), { status: res.status, }); }
const data = await res.json();
return new Response( JSON.stringify({ pageviews: data.pageviews, visitors: data.visitors, visits: data.visits, bounces: data.bounces, totaltime: data.totaltime, updatedAt: Date.now(), }), { headers: { "Access-Control-Allow-Origin": "*", "Access-Control-Allow-Methods": "GET, POST, PUT, DELETE, PATCH, OPTIONS", "Access-Control-Allow-Headers": "Content-Type, Authorization", "Access-Control-Max-Age": "86400", }, } ); } catch (e) { return new Response( JSON.stringify({ error: e?.message || "Internal error" }), { status: 500 } ); } }
|
简单解释一下,获取统计信息主要是访问https://api.umami.is/v1/websites/${WEBSITE_ID}/stats获得,其中 startAt 和 endAt是必须参数,他们是以毫秒为单位的时间戳,createdAt修改为你的网站接入统计的日期,然后endAt使用当前时间戳既可以获取所有时间段的访问量统计,返回值中的pageviews 即为浏览量,而visitors 即为非冗余游客量。当然,访问的时候需要带上Authorization token。
如何获取Authorization token ?
访问这个链接 获取即可,注意保密!
如何获取网站ID
鼠标点击你的网站名字,新打开的url最后面结尾那一串字符串就是你的网站ID.
edgeOne的演示地址:
然后你就可以在你的页脚处添加一个html 如下:
1
| <span id="umami_container_site_pv">本站总访问量<span id="umami_value_site_pv"></span>次, 总访客量<span id="umami_value_site_v"></span>人</span>
|
然后写一个javascript脚本来填充数据.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| (function () { const API_URL = "https://landing-page-demo-77qf8sw1.edgeone.app/umami";
const pvEl = document.getElementById("umami_value_site_pv"); const vEl = document.getElementById("umami_value_site_v");
if (!pvEl || !vEl) return;
fetch(API_URL, { cache: "no-store" }) .then((res) => res.json()) .then((data) => { if (typeof data.pageviews === "number") { pvEl.textContent = data.pageviews.toLocaleString(); } if (typeof data.visitors === "number") { vEl.textContent = data.visitors.toLocaleString(); } }) .catch(() => { pvEl.textContent = "-"; vEl.textContent = "-"; }); })();
|
爬虫抓取
该方案来自博客二叉树树
首先我们启用分享URL
注意这里的 7PoDRgCzHFTs2vWB ,每个站点都不一样
接着我们请求 https://cloud.umami.is/analytics/us/api/share/7PoDRgCzHFTs2vWB,得到 注意,这里的 us 为你创建的账号区域,美国为us,欧盟为eu.
1 2 3 4
| { "websiteId": "a66a5fd4-98b0-4108-8606-cb7094f380ac", "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3ZWJzaXRlSWQiOiJhNjZhNWZkNC05OGIwLTQxMDgtODYwNi1jYjcwOTRmMzgwYWMiLCJpYXQiOjE3NTA4MDIwMzB9.X5GQT5kslh6r25sFlap4Asz1NDA7mN3kcZW8wqbrnBc" }
|
再接着我们请求,携带请求头 x-umami-share-token 值为上一步获得的Token
https://cloud.umami.is/analytics/us/api/websites/a66a5fd4-98b0-4108-8606-cb7094f380ac/stats?startAt=0&endAt=1750805999999&unit=hour&timezone=Asia/Hong_Kong&path=eq./posts/cf-fastip/&compare=false
这里解释几个关键Params,其他的照搬
startAt:统计开始时间。Unix时间戳,我们填写为0让Umami从1970年开始统计
endAt:统计结束时间。Unix时间戳,我们可以使用 Date.now() ,即当前时间,和startAt参数联动即可实现统计总浏览量
path:要查询的路径,填写为你的文章页去除了Host的路径,如 /posts/hello 。注意!Umami会将 /posts/hello 和 /posts/hello/ 视为两个不同的路径,请注意你的博客框架是否使用 /。需要使用 eq. 前缀来进行精确匹配,例如 path=eq./posts/hello/
你会得到
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| { "pageviews": 1655, "visitors": 343, "visits": 411, "bounces": 183, "totaltime": 30592, "comparison": { "pageviews": 0, "visitors": 0, "visits": 0, "bounces": 0, "totaltime": 0 } }
|
前面已经讲过了,pageviews 即浏览量。 visitors 即访问人数。
那么,重复前面的步骤,我们就可以修改前端的javascript脚本来直接获取该逆向的结果:
依旧创建 html
1
| <span id="umami_container_site_pv">本站总访问量<span id="umami_value_site_pv"></span>次, 总访客量<span id="umami_value_site_v"></span>人</span>
|
然后写一个javascript脚本来填充数据.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| (function () { const websiteID = "a66a5fd4-98b0-4108-8606-cb7094f380ac"; const startAt = 0; const endAt = new Date().getTime();
const API_URL = `https://cloud.umami.is/analytics/us/api/websites/${websiteID}/stats?startAt=${startAt}&endAt=${endAt}`;
const pvEl = document.getElementById("umami_value_site_pv"); const vEl = document.getElementById("umami_value_site_v");
if (!pvEl || !vEl) return;
fetch(API_URL, { headers: { "x-umami-share-token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ3ZWJzaXRlSWQiOiJhNjZhNWZkNC05OGIwLTQxMDgtODYwNi1jYjcwOTRmMzgwYWMiLCJpYXQiOjE3NTA4MDIwMzB9.X5GQT5kslh6r25sFlap4Asz1NDA7mN3kcZW8wqbrnBc", }, }) .then((res) => res.json()) .then((data) => { if (typeof data.pageviews === "number") { console.log(data.pageviews); pvEl.textContent = data.pageviews.toLocaleString(); } if (typeof data.visitors === "number") { console.log(data.visitors); vEl.textContent = data.visitors.toLocaleString(); } }) .catch(() => { pvEl.textContent = "-"; vEl.textContent = "-"; }); })();
|
因为我想获取全站的总体统计信息,因此只需要两个请求参数startAt和endAt即可。
完!