Remix+CloudflareでWebサイトを作る 35(PV数は表示するべきか、GTM導入テスト、各サイトのGTM導入事情・収益導線調査、アフィリンクの値段表示、Slug)
【2024-10-07】記事毎のPV数は表示するべきか考える
背景
ページごとのPV数を表示したいと思っている。
1日1回Google Analyticsで取得して、記事のテーブルのpv
みたいなカラムを更新するべきなんだろうか?
メリット
- コンテンツの透明性が高まる
- ユーザーの関心を引ける
デメリット
- 定期的に(1日1回とか)全行に更新処理かけるので負荷がデカくなっていく一方
そもそも既存のサイトってどんな感じ?
Webサイト | 記事毎のPV表示 | ランキングのPV表示 |
---|---|---|
Gigazine | なし | なし |
GIZMODO | なし | あり |
ねとらぼ | なし | なし |
IT Media | なし | なし |
U-site | なし | なし |
Togetter | あり | なし |
こうやって調べてみるとそもそもPV数の表示ってあんまりなさそう。
更新コスト考えたらなくて良いかも。
ランキング表示があるからPV数字は取ってるけど、あまり表示していないもんなんだな。
自分も色々なサイト見てる時PV数を意識してることってかなり少ない。
X(Twitter)はちょっっっと見るかもだけど。
結論
- PV数は画面に表示しない
- ランキングにだけ表示する(かもしれない)
- この場合もGoogle Analyticsで取得したデータそのまま表示すれば良いのでDBに変更なし
by ChatGPT
【2024-10-09】GTMを導入しようとしたらHydration関連のとか色々エラー出た
背景
GTMを導入したい。
Google Analyticsのときと同じく以下のコードを書いてbodyにぶち込む。
function GoogleTagManagerScript({ gtmId }: { gtmId: string }) {
return (
<>
<script
async
src={`https://www.googletagmanager.com/ns.html?id=${gtmId}`}
/>
<script
async
id="gtm-init"
dangerouslySetInnerHTML={{
__html: `
(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${gtmId}');
`,
}}
/>
</>
);
}
エラー
# その1
Warning: Prop src did not match. Server: "
# その2
Uncaught Error: Hydration failed because the initial UI does not match what was rendered on the server.
# その3
Warning: An error occurred during hydration. The server HTML was replaced with client content in <#document>.
# その4
Uncaught Error: There was an error while hydrating. Because the error happened outside of a Suspense boundary, the entire root will switch to client rendering.
解決方法
まんまこれ採用して解決。
const
は使えない
カスタムHTMLでタグを作成するときに「カスタムHTML」という種類にして自由にscriptを書けるんだけど、const
を使うと公開時に怒られるのでvar
を使わなくてはいけない。
This language feature is only supported for ECMASCRIPT_2015 mode or better: const declaration.
GTMを公開してもすぐに反映されない
これ系のツール使ってると陥りがちなやーつ。
実測値で12分かかった。
ローカルデバッグするときは少しずつやってると日が暮れるから、一気にいろいろなとこデバッグして、変更されたことがわかるようにせねば。
GTMはAdBlockがあると動作しない
シークレットモードだと動くけど、通常のブラウザだと動かないパターンがあることに気づいたけど、差分はAdBlockが入ってるかどうかだった。
つまり、GTMはAdBlockが入っていると正常に動作しない。
AdBlockでAmazon広告消えるところはGTM使ってるのね〜。
自前実装するか😞
【2024-10-12】広告の表示や収益導線について色々調べる。GTMは使ってる?
調査結果
GTM
- 使ってるサイトめっちゃ多い(使ってないことろないんじゃないか)
Amazonリンク
- たいていGTM使ってる
- GIZMODEはGTM使ってない
- が、ずっと同じ商品が表示されているので固定で埋め込まれていて外側から動的に変えるようなシステムにはなってなさそう
GTMを使わないで収益をあげる方法
-
- 直にURLを貼るタイプのアフィリエイト(Amaozn、楽天)
-
- スポンサーを募集して広告を表示する
-
- スポンサーを募集して記事を作成する
-
- その他
- PixivのFANBOX
- 有料note
感想
自分の場合はWordpressでもlivedoor blogでもない完全な自前実装だからアフィリンクはAdBlockの対象から外れさせることはできそう。
広告の数とか、場所についてもそれぞれのサイトでまとめてみようかと思ったけど、「基本的には空いている場所にできるだけ貼る」「場合によってはポップオーバー型のも出す」みたいな感じなのかな。
参考にしないで自分で試しながらPVとか回遊率とか収益見ながら最適解みつけて行くで良い気がする。
以下の記事にパターンが書かれてある。
アドセンス広告の定番の貼る位置を紹介!視線の動きに合わせて設置しよう | 初心者のためのブログ始め方講座
みんなAdBlockの流行でどれくらい収益減ったんだろう?
調査内容
ゲーム速報@JIN
Amazon広告も全部消えるので全部GTM使ってそう 。
使用しているのはlivedoor blog。
GIZMODE
「PR」をつけたうえで表示され続けているのでGTMではなさそう。
他のサイトと違うのは 「Sponsored by xxx」と書いてある記事があること。
ここをクリックすると広告のように外部サイトに飛ぶのではなく、GIZMODEが作成した記事へリンクが飛ぶ(以下の画像の右下の広告をクリック)。
utm_source
とかutm_campaign
とかのクエリがついてる。
https://www.gizmodo.jp/2024/10/jbl-tour-pro-3.html?utm_source=voluntary&utm_medium=cxense-ad&utm_campaign=176308390
ねとらぼ
GTM使ってる。
togetter
GTM使ってる。
Gigazine
Googleの広告。
しかもここはポップオーバータイプのも出てくるサイト。
すまほん!!
広告の表示方法をかえるというより、ドメインを指定することでブロックの解除をお願いする記事。
使用しているのはWordpress。
代替策として、PIXIVのFANBOXやnote、スポンサー募集で収益をあげているっぽい。
下部にnoteへの導線も用意してある。
GTMの設定で広告の表示を許可するポップアップを表示する機能がある
Google AdSense 広告ブロックによる損失収益の回復について【AdBlockを回避する方法】-今日もたかいびき
そして、広告ブロックによる損失収益のデータも見れるのか。おもろ。
すまほん!!の右下に表示されてる「X フォローする」ボタンを押してクリックして思ったんだけど、以下のURLにアクセスするとフォローするボタンがモーダルで出てきた状態になるのか。
【2024-10-12】アフィリンクに値段は表示するか
値段の情報は取得するべきなのか気になったので今まで自分が見てきたサイトってどうだったかな?と思い調査。
Googaleのスポンサーでは表示する。
この機能ホント便利だ。
mybest
ふと思ったけどmybestってURLはslugじゃなくIDなんだ。
SEOとかこだわりそうだけどslugってそんなに影響力デカくないのかな?
基本的に表示しているが、表示していない場合もある。
以下では「楽天市場」をクリックすると商品のURLではなく、検索結果に遷移する。
どうやら、商品が楽天市場にないため、商品自体のURLは貼れない状態っぽい。
なるほど。
売れ筋商品一覧に飛ばす導線もある。
こういうのはあんまり見ないな。
個人ブログ
表示しないパターン。なお商品名をクリックすることもできてAmazonに飛ぶ。
値段なんて定期的に変わるし、表示しなくてもいいよなとも思う。
自分は値段が書いてあるからクリックしようとは頭の中でなってなくて、なんとなくクリックしてAmaozon内で具体的に値段や商品内容を確認している気がする。
【2024-10-12】slugつけるか問題
結論
- めんどいけどやれるならやったほうが良さそう
- slugだと記事ではないが表示したいものとかも管理できるの良さそう
- 例えば以下のように広告についての説明を書きたい場合も記事として書けると多言語で動的に内容を変えられるてとても便利
- ただその使い方するなら記事一覧には表示させたくないからそういうフラグも必要になるのか?
SEOへの影響
色々見てみるとあるはあるっぽいけどid形式のサイトでも検索結果に高いランキングで出てくるものもあるのでその度合がどれくらいなのかはわからなかった。
調査
サイト名 | 形式 | URLの例 |
---|---|---|
mybest | ID | https://my-best.com/1038 |
Togetter | ID | https://togetter.com/li/2448307 |
Gigazine | yyyymmdd-articleName | https://gigazine.net/news/20241007-ubisoft-director-blames-gamers/ |
すまほん!! | yyyymmdd-articleName | https://smhn.info/202312-please-exclude-our-domain-from-your-ad-blocker |
ねとらぼ | yymm/dd/ID | https://nlab.itmedia.co.jp/nl/articles/2410/11/news023.html |
GIZMODE | yyyy/mm/articleName | https://www.gizmodo.jp/2024/10/avex-sarf.html |
U-Site | articleName | https://u-site.jp/lecture/usability-in-architecture-2 |
前も調べてた
slugのzodバリデーションを作った。
export const slug = () =>
z.string({ required_error: "必須項目です" }).superRefine((value, ctx) => {
const yearMonthPattern = /^([0-9]{6})/;
const yearMonthMatch = value.match(yearMonthPattern);
if (!yearMonthMatch) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "「202410-」のように年月を先頭に入れてください",
});
return;
}
const year = parseInt(yearMonthMatch[1].substring(0, 4), 10);
const month = yearMonthMatch[1].substring(4, 6);
if (year < 1900) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "先頭の4文字は1900以上の値にしてください",
});
return;
}
if (!/^(0[1-9]|1[0-2])$/.test(month)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "先頭5、6文字目は01〜12の値にしてください",
});
return;
}
if (!/^[a-z0-9-]+$/.test(value)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "英語とハイフンのみ使用してください",
});
return;
}
if (value !== value.toLowerCase()) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "英小文字のみ使用できます",
});
return;
}
if (/^[-]|[-]$/.test(value)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "先頭と末尾にハイフンは使用できません",
});
return;
}
if (/--/.test(value)) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: "連続してハイフンは使用できません",
});
return
}
});