2026.06.16 | youres | 4次围观
为什么要监控UTM参数丢失
做营销投放的同事都遇到过这种情况:花了钱推的链接,到GA4一看流量归因全是direct,UTM参数在重定向过程中被剥离了,却没人知道。等发现的时候,已经浪费了几天的预算。
手动检查不现实,链接成百上千。需要一个自动化方案:定时批量检测UTM参数是否保留,一旦发现丢失,立刻推送到钉钉群,让负责人第一时间处理。
curl检测UTM参数是否丢失的原理
核心思路很简单:用curl模拟用户请求,追踪重定向全过程,检查最终URL里是否还带着UTM参数。
# 追踪重定向并获取最终URL
curl -L -s -o /dev/null -w "%{url_effective}" "http://example.com/mkt?utm_source=baidu&utm_medium=cpc"
如果输出的url_effective里没有utm_source、utm_medium,说明参数在重定向过程中丢失了。
脚本一:基础版UTM参数丢失检测+钉钉告警
先上完整可运行的脚本。这个版本适合刚开始接入告警的团队,逻辑清晰,改改配置就能用。
#!/bin/bash
# === 配置区域 ===
WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN"
SECRET="YOUR_SECRET"
URL_LIST=(
"https://www.youres.cn/promotion?utm_source=wechat&utm_medium=social"
"https://www.youres.cn/activity?utm_source=baidu&utm_medium=cpc"
)
# === 生成钉钉签名 ===
generate_sign() {
local timestamp=$(date +%s%3N)
local string_to_sign="${timestamp}\n${SECRET}"
local sign=$(echo -ne "$string_to_sign" | openssl dgst -sha256 -hmac "${SECRET}" -binary | base64 | jq -sRr @uri)
echo "$timestamp" "$sign"
}
# === 检测UTM参数 ===
check_utm() {
local url="$1"
local final_url=$(curl -L -s -o /dev/null -w "%{url_effective}" "$url")
if [[ "$final_url" != *"utm_source="* ]]; then
echo "UTM丢失: $url"
echo " 最终跳转: $final_url"
return 1
else
echo "UTM正常: $url"
return 0
fi
}
# === 发送钉钉告警 ===
send_dingtalk() {
local msg="$1"
read -r ts sign <<< $(generate_sign)
local webhook_url="${WEBHOOK}×tamp=${ts}&sign=${sign}"
curl -s -X POST "$webhook_url" \
-H "Content-Type: application/json" \
-d "{\"msgtype\":\"text\",\"text\":{\"content\":\"${msg}\"}}"
}
# === 主流程 ===
main() {
local alert_msg=""
for url in "${URL_LIST[@]}"; do
if ! check_utm "$url"; then
alert_msg="${alert_msg}UTM参数丢失\nURL: ${url}\n"
fi
done
if [ -n "$alert_msg" ]; then
send_dingtalk "$alert_msg"
fi
}
main
脚本二:生产级批量检测+详细告警信息
基础版能跑,但生产环境需要更多信息:哪个参数丢了、跳了几次、最终跳到哪里。这个版本把这些细节都加上了。
#!/bin/bash
# 生产级UTM参数丢失检测脚本
URL_FILE="/opt/utm_check/url_list.txt"
LOG_FILE="/opt/utm_check/utm_check.log"
WEBHOOK="https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN"
SECRET="YOUR_SECRET"
# 生成签名(同上,省略)
generate_sign() { ... }
# 详细检测单条URL
detect_utm_detail() {
local url="$1"
local result=$(curl -L -s -o /dev/null --max-redirs 10 \
-w "url_effective: %{url_effective}\nnum_redirects: %{num_redirects}\nhttp_code: %{http_code}\n" "$url" 2>/dev/null)
local final_url=$(echo "$result" | grep "url_effective" | sed 's/url_effective: //')
local redirects=$(echo "$result" | grep "num_redirects" | awk '{print $2}')
# 检查必要的UTM参数
local missing=""
for param in utm_source utm_medium; do
if [[ "$final_url" != *"$param="* ]]; then
missing="$missing $param"
fi
done
if [ -n "$missing" ]; then
echo "ALERT|URL:$url|FINAL:$final_url|REDIRECTS:$redirects|MISSING:$missing"
return 1
fi
return 0
}
# 批量检测
batch_check() {
local alert_count=0
local alert_detail=""
while IFS= read -r url || [ -n "$url" ]; do
[ -z "$url" ] && continue
result=$(detect_utm_detail "$url")
if [ $? -ne 0 ]; then
alert_count=$((alert_count + 1))
alert_detail="${alert_detail}第${alert_count}条\n${result}\n\n"
fi
done < "$URL_FILE"
if [ $alert_count -gt 0 ]; then
local msg="UTM参数丢失告警\n检测时间: $(date '+%Y-%m-%d %H:%M:%S')\n异常数量: ${alert_count}\n\n${alert_detail}"
send_dingtalk "$msg"
echo "[$(date)] ALERT: $alert_count URLs have UTM lost" >> "$LOG_FILE"
fi
}
batch_check
脚本三:crontab定时任务+告警去重
最后一版加上了告警去重:同一个URL连续检测3次都异常才告警,避免网络抖动导致的误报。
#!/bin/bash
# 带去重逻辑的UTM告警脚本
STATE_DIR="/opt/utm_check/state"
mkdir -p "$STATE_DIR"
check_with_dedup() {
local url="$1"
local state_file="$STATE_DIR/$(echo -n "$url" | md5sum | awk '{print $1}').state"
local max_fail=3
if ! detect_utm_detail "$url" > /dev/null 2>&1; then
# 检测失败,计数+1
local fail_count=0
[ -f "$state_file" ] && fail_count=$(cat "$state_file")
fail_count=$((fail_count + 1))
echo "$fail_count" > "$state_file"
if [ $fail_count -ge $max_fail ]; then
# 达到阈值,发送告警并重置计数
send_dingtalk "UTM参数持续丢失\nURL: $url\n已连续${max_fail}次检测异常"
echo "0" > "$state_file"
fi
else
# 检测正常,重置计数
echo "0" > "$state_file"
fi
}
配置crontab每10分钟跑一次:
*/10 * * * * /opt/utm_check/utm_dedup_check.sh >> /opt/utm_check/cron.log 2>&1
钉钉签名认证踩坑记录
钉钉机器人加签认证有几个坑,都是实际对接时踩过的:
- 时间戳单位是毫秒:用
date +%s%3N,不是date +%s(秒级),否则签名验证会报"timestamp is invalid" - 签名字符串格式:必须是
${timestamp}\n${secret},中间是换行符\n,不是空格 - Base64后需要urlencode:直接用base64输出会有换行符,必须先urlencode再拼到URL里
- Shell里base64输出处理:用
base64 -w 0禁止换行,否则签名会带换行符导致验证失败
相关文章
总结
UTM参数丢失的代价是被掩盖的真相:你不知道哪个渠道真的带来转化,优化投放只能靠猜。用上面三个脚本,从基础检测到生产级去重告警,一步步把营销追踪的监控盲点补上。10分钟配置好,后面就是它帮你盯着。
版权声明
本文仅代表个人观点。
本文系AI辅助作者原创,未经许可,转载请保留原文链接。

发表评论