[{"data":1,"prerenderedAt":1288},["ShallowReactive",2],{"content:\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Fmeasuring-bfcache-hit-rate-in-rum":3,"surroundings:\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Fmeasuring-bfcache-hit-rate-in-rum":1279},{"id":4,"title":5,"body":6,"description":1259,"extension":1260,"meta":1261,"navigation":1272,"path":1273,"seo":1274,"stem":1277,"__hash__":1278},"content\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Fmeasuring-bfcache-hit-rate-in-rum\u002Findex.md","Measuring bfcache Hit Rate in RUM",{"type":7,"value":8,"toc":1242},"minimark",[9,14,38,50,201,206,247,251,264,273,281,290,401,405,410,638,641,645,889,892,896,938,942,945,1020,1024,1027,1031,1050,1054,1080,1084,1097,1103,1112,1118,1122,1125,1132,1136,1148,1161,1173,1182,1191,1200,1204,1227,1232,1235,1238],[10,11,13],"h1",{"id":12},"how-to-measure-bfcache-hit-rate-in-real-user-monitoring","How to Measure bfcache Hit Rate in Real-User Monitoring",[15,16,17,18,23,24,28,29,33,34,37],"p",{},"This guide sets up the field metric for ",[19,20,22],"a",{"href":21},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002F","Back\u002FForward Cache (bfcache)",", part of ",[19,25,27],{"href":26},"\u002Fadvanced-caching-strategies-cdn-architecture\u002F","Advanced Caching Strategies & CDN Architecture",". DevTools tells you whether a page ",[30,31,32],"em",{},"can"," be restored on your machine; only field data tells you how often it ",[30,35,36],{},"is"," restored for real users, on real devices, with real third-party scripts and consent states — and why it is not when it fails.",[15,39,40,41,45,46,49],{},"The core measurement is simple: on every page show, record whether the page was restored (",[42,43,44],"code",{},"event.persisted",") or loaded, and for back\u002Fforward loads that were not restored, record the browser's ",[42,47,48],{},"notRestoredReasons",". From that you compute a hit rate per template and a ranked list of blockers. The subtleties are in counting correctly — distinguishing back\u002Fforward navigations from other loads, avoiding double counting, and handling browsers that expose less information.",[15,51,52],{},[53,54,60,61,60,68,60,72,60,75,60,93,60,101,60,107,60,115,60,122,60,127,60,133,60,137,60,140,60,144,60,147,60,151,60,154,60,157,60,161,60,164,60,167,60,170,60,174,60,177,60,180,60,189,60,193,60,197,60],"svg",{"viewBox":55,"width":56,"role":57,"ariaLabel":58,"style":59},"0 0 760 149","100%","img","Pipeline from the pageshow event through classification and reason collection to a hit-rate dashboard.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[62,63],"rect",{"className":64,"x":66,"y":66,"width":56,"height":56,"fill":67},[65],"svg-canvas","0","#ffffff",[69,70,71],"title",{},"From page show to bfcache dashboard",[73,74,58],"desc",{},[76,77,78],"defs",{},[79,80,87],"marker",{"id":81,"viewBox":82,"refX":83,"refY":84,"markerWidth":85,"markerHeight":85,"orient":86},"fa8f3b3fc5","0 0 10 10","9","5","7","auto-start-reverse",[88,89],"path",{"d":90,"fill":91,"style":92},"M0 0 L10 5 L0 10 z","currentColor","fill-opacity:0.7",[62,94],{"x":95,"y":95,"width":96,"height":97,"rx":98,"fill":99,"stroke":91,"style":100},"1","758","147","10","none","stroke-opacity:0.18",[102,103,71],"text",{"x":104,"y":105,"fill":91,"style":106},"28.0","34.0","font-size:16px;font-weight:700",[62,108],{"x":104,"y":109,"width":110,"height":111,"rx":112,"fill":113,"stroke":113,"style":114},"56.0","108.8","71.0","6","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[102,116,121],{"x":117,"y":118,"fill":91,"style":119,"textAnchor":120},"82.4","78.0","font-size:13px;font-weight:700","middle","pageshow",[102,123,126],{"x":117,"y":124,"fill":91,"style":125,"textAnchor":120},"96.0","font-size:12px","persisted?",[62,128],{"x":129,"y":109,"width":110,"height":111,"rx":112,"fill":130,"stroke":131,"style":132},"176.8","#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[102,134,136],{"x":135,"y":118,"fill":91,"style":119,"textAnchor":120},"231.2","Classify",[102,138,139],{"x":135,"y":124,"fill":91,"style":125,"textAnchor":120},"restore \u002F bf-miss \u002F",[102,141,143],{"x":135,"y":142,"fill":91,"style":125,"textAnchor":120},"112.0","other",[62,145],{"x":146,"y":109,"width":110,"height":111,"rx":112,"fill":113,"stroke":113,"style":114},"325.6",[102,148,150],{"x":149,"y":118,"fill":91,"style":119,"textAnchor":120},"380.0","Reasons",[102,152,153],{"x":149,"y":124,"fill":91,"style":125,"textAnchor":120},"misses only",[62,155],{"x":156,"y":109,"width":110,"height":111,"rx":112,"fill":113,"stroke":113,"style":114},"474.4",[102,158,160],{"x":159,"y":118,"fill":91,"style":119,"textAnchor":120},"528.8","Beacon",[102,162,163],{"x":159,"y":124,"fill":91,"style":125,"textAnchor":120},"template +",[102,165,166],{"x":159,"y":142,"fill":91,"style":125,"textAnchor":120},"browser",[62,168],{"x":169,"y":109,"width":110,"height":111,"rx":112,"fill":113,"stroke":113,"style":114},"623.2",[102,171,173],{"x":172,"y":118,"fill":91,"style":119,"textAnchor":120},"677.6","Dashboard",[102,175,176],{"x":172,"y":124,"fill":91,"style":125,"textAnchor":120},"hit rate + top",[102,178,179],{"x":172,"y":142,"fill":91,"style":125,"textAnchor":120},"reasons",[181,182],"line",{"x1":183,"y1":184,"x2":185,"y2":184,"stroke":91,"strokeWidth":186,"style":187,"markerEnd":188},"136.8","91.5","174.8","1.5","stroke-opacity:0.6","url(#fa8f3b3fc5)",[181,190],{"x1":191,"y1":184,"x2":192,"y2":184,"stroke":91,"strokeWidth":186,"style":187,"markerEnd":188},"285.6","323.6",[181,194],{"x1":195,"y1":184,"x2":196,"y2":184,"stroke":91,"strokeWidth":186,"style":187,"markerEnd":188},"434.4","472.4",[181,198],{"x1":199,"y1":184,"x2":200,"y2":184,"stroke":91,"strokeWidth":186,"style":187,"markerEnd":188},"583.2","621.2",[202,203,205],"h2",{"id":204},"rapid-diagnosis","Rapid Diagnosis",[207,208,209,217,227,241],"ul",{},[210,211,212,216],"li",{},[213,214,215],"strong",{},"Do you know your restoration rate?"," If not, start here; most teams are surprised by how low it is.",[210,218,219,222,223,226],{},[213,220,221],{},"Does your RUM count restored pages at all?"," Some setups only fire on ",[42,224,225],{},"load",", so restorations are invisible.",[210,228,229,232,233,236,237,240],{},[213,230,231],{},"Are back\u002Fforward reloads distinguished from fresh loads?"," Navigation Timing's ",[42,234,235],{},"type"," is ",[42,238,239],{},"back_forward"," for them.",[210,242,243,246],{},[213,244,245],{},"Do you collect reasons?"," Without reasons, a low rate is not actionable.",[202,248,250],{"id":249},"root-cause-analysis-why-bfcache-is-hard-to-see","Root Cause Analysis: Why bfcache Is Hard to See",[15,252,253,256,257,260,261,263],{},[213,254,255],{},"1. Restorations do not fire load events."," Analytics tied to ",[42,258,259],{},"DOMContentLoaded","\u002F",[42,262,225],{}," never see them.",[15,265,266,269,270,272],{},[213,267,268],{},"2. Misses look like normal loads."," A back navigation that reloads is a regular page view unless you check ",[42,271,235],{},".",[15,274,275,60,278,280],{},[213,276,277],{},"3. Reasons are browser-specific.",[42,279,48],{}," is Chromium-only; Safari and Firefox users contribute hit\u002Fmiss data without reasons.",[15,282,283,286,287,289],{},[213,284,285],{},"4. Evictions look like misses."," A page evicted from bfcache for memory reasons reloads like an ineligible one; ",[42,288,48],{}," helps separate them.",[15,291,292],{},[53,293,60,296,60,299,60,302,60,304,60,307,60,309,60,314,60,321,60,325,60,329,60,332,60,336,60,340,60,344,60,346,60,349,60,351,60,354,60,357,60,361,60,363,60,365,60,367,60,370,60,373,60,376,60,378,60,381,60,383,60,386,60,389,60,392,60,394,60,397,60,399,60],{"viewBox":294,"width":56,"role":57,"ariaLabel":295,"style":59},"0 0 760 228","How to classify page shows from pageshow persisted and navigation type into bfcache outcomes.",[62,297],{"className":298,"x":66,"y":66,"width":56,"height":56,"fill":67},[65],[69,300,301],{},"Classifying each page show",[73,303,295],{},[62,305],{"x":95,"y":95,"width":96,"height":306,"rx":98,"fill":99,"stroke":91,"style":100},"226",[102,308,301],{"x":104,"y":105,"fill":91,"style":106},[62,310],{"x":104,"y":109,"width":311,"height":312,"rx":66,"fill":91,"stroke":91,"style":313},"135.8","30.0","fill-opacity:0.06;stroke-opacity:0.4",[102,315,320],{"x":316,"y":317,"fill":91,"style":318,"textAnchor":319},"38.0","75.5","font-size:12.5px;font-weight:700","start","pageshow.persisted",[62,322],{"x":323,"y":109,"width":324,"height":312,"rx":66,"fill":91,"stroke":91,"style":313},"163.8","284.1",[102,326,328],{"x":327,"y":317,"fill":91,"style":318,"textAnchor":120},"305.8","Navigation type",[62,330],{"x":331,"y":109,"width":324,"height":312,"rx":66,"fill":91,"stroke":91,"style":313},"447.9",[102,333,335],{"x":334,"y":317,"fill":91,"style":318,"textAnchor":120},"589.9","Classification",[62,337],{"x":104,"y":338,"width":311,"height":312,"rx":66,"fill":99,"stroke":91,"style":339},"86.0","stroke-opacity:0.35",[102,341,343],{"x":316,"y":342,"fill":91,"style":318,"textAnchor":319},"105.5","true",[62,345],{"x":323,"y":338,"width":324,"height":312,"rx":66,"fill":99,"stroke":91,"style":339},[102,347,348],{"x":327,"y":342,"fill":91,"style":125,"textAnchor":120},"(n\u002Fa — restored)",[62,350],{"x":331,"y":338,"width":324,"height":312,"rx":66,"fill":113,"stroke":113,"style":114},[102,352,353],{"x":334,"y":342,"fill":91,"style":125,"textAnchor":120},"bfcache hit",[62,355],{"x":104,"y":356,"width":311,"height":312,"rx":66,"fill":99,"stroke":91,"style":339},"116.0",[102,358,360],{"x":316,"y":359,"fill":91,"style":318,"textAnchor":319},"135.5","false",[62,362],{"x":323,"y":356,"width":324,"height":312,"rx":66,"fill":99,"stroke":91,"style":339},[102,364,239],{"x":327,"y":359,"fill":91,"style":125,"textAnchor":120},[62,366],{"x":331,"y":356,"width":324,"height":312,"rx":66,"fill":130,"stroke":131,"style":132},[102,368,369],{"x":334,"y":359,"fill":91,"style":125,"textAnchor":120},"bfcache miss",[62,371],{"x":104,"y":372,"width":311,"height":312,"rx":66,"fill":99,"stroke":91,"style":339},"146.0",[102,374,360],{"x":316,"y":375,"fill":91,"style":318,"textAnchor":319},"165.5",[62,377],{"x":323,"y":372,"width":324,"height":312,"rx":66,"fill":99,"stroke":91,"style":339},[102,379,380],{"x":327,"y":375,"fill":91,"style":125,"textAnchor":120},"navigate \u002F reload",[62,382],{"x":331,"y":372,"width":324,"height":312,"rx":66,"fill":91,"stroke":91,"style":313},[102,384,385],{"x":334,"y":375,"fill":91,"style":125,"textAnchor":120},"not a bfcache candidate",[62,387],{"x":104,"y":388,"width":311,"height":312,"rx":66,"fill":99,"stroke":91,"style":339},"176.0",[102,390,360],{"x":316,"y":391,"fill":91,"style":318,"textAnchor":319},"195.5",[62,393],{"x":323,"y":388,"width":324,"height":312,"rx":66,"fill":99,"stroke":91,"style":339},[102,395,396],{"x":327,"y":391,"fill":91,"style":125,"textAnchor":120},"prerender activation",[62,398],{"x":331,"y":388,"width":324,"height":312,"rx":66,"fill":91,"stroke":91,"style":313},[102,400,385],{"x":334,"y":391,"fill":91,"style":125,"textAnchor":120},[202,402,404],{"id":403},"step-by-step-resolution","Step-by-Step Resolution",[406,407,409],"h3",{"id":408},"_1-classify-every-page-show","1. Classify every page show",[411,412,417],"pre",{"className":413,"code":414,"language":415,"meta":416,"style":416},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","function classifyShow(event) {\n  if (event.persisted) return 'hit';\n  const nav = performance.getEntriesByType('navigation')[0];\n  return nav?.type === 'back_forward' ? 'miss' : 'none';\n}\naddEventListener('pageshow', (event) => {\n  const outcome = classifyShow(event);\n  if (outcome === 'none') return;\n  send({ bf: outcome, template: document.body.dataset.template, ...(outcome === 'miss' ? reasons() : {}) });\n});\n\u002F\u002F trade-off: pageshow with persisted=false fires on the initial load too; the\n\u002F\u002F navigation type check is what isolates back\u002Fforward misses.\n","javascript","",[42,418,419,442,461,493,522,528,553,568,586,619,625,632],{"__ignoreMap":416},[420,421,423,427,431,435,439],"span",{"class":181,"line":422},1,[420,424,426],{"class":425},"sPARh","function",[420,428,430],{"class":429},"smZ65"," classifyShow",[420,432,434],{"class":433},"saISM","(",[420,436,438],{"class":437},"sQw3B","event",[420,440,441],{"class":433},") {\n",[420,443,445,448,451,454,458],{"class":181,"line":444},2,[420,446,447],{"class":425},"  if",[420,449,450],{"class":433}," (event.persisted) ",[420,452,453],{"class":425},"return",[420,455,457],{"class":456},"sZ8jY"," 'hit'",[420,459,460],{"class":433},";\n",[420,462,464,467,471,474,477,480,482,485,488,490],{"class":181,"line":463},3,[420,465,466],{"class":425},"  const",[420,468,470],{"class":469},"sPXB4"," nav",[420,472,473],{"class":425}," =",[420,475,476],{"class":433}," performance.",[420,478,479],{"class":429},"getEntriesByType",[420,481,434],{"class":433},[420,483,484],{"class":456},"'navigation'",[420,486,487],{"class":433},")[",[420,489,66],{"class":469},[420,491,492],{"class":433},"];\n",[420,494,496,499,502,505,508,511,514,517,520],{"class":181,"line":495},4,[420,497,498],{"class":425},"  return",[420,500,501],{"class":433}," nav?.type ",[420,503,504],{"class":425},"===",[420,506,507],{"class":456}," 'back_forward'",[420,509,510],{"class":425}," ?",[420,512,513],{"class":456}," 'miss'",[420,515,516],{"class":425}," :",[420,518,519],{"class":456}," 'none'",[420,521,460],{"class":433},[420,523,525],{"class":181,"line":524},5,[420,526,527],{"class":433},"}\n",[420,529,531,534,536,539,542,544,547,550],{"class":181,"line":530},6,[420,532,533],{"class":429},"addEventListener",[420,535,434],{"class":433},[420,537,538],{"class":456},"'pageshow'",[420,540,541],{"class":433},", (",[420,543,438],{"class":437},[420,545,546],{"class":433},") ",[420,548,549],{"class":425},"=>",[420,551,552],{"class":433}," {\n",[420,554,556,558,561,563,565],{"class":181,"line":555},7,[420,557,466],{"class":425},[420,559,560],{"class":469}," outcome",[420,562,473],{"class":425},[420,564,430],{"class":429},[420,566,567],{"class":433},"(event);\n",[420,569,571,573,576,578,580,582,584],{"class":181,"line":570},8,[420,572,447],{"class":425},[420,574,575],{"class":433}," (outcome ",[420,577,504],{"class":425},[420,579,519],{"class":456},[420,581,546],{"class":433},[420,583,453],{"class":425},[420,585,460],{"class":433},[420,587,589,592,595,598,601,603,605,607,610,613,616],{"class":181,"line":588},9,[420,590,591],{"class":429},"  send",[420,593,594],{"class":433},"({ bf: outcome, template: document.body.dataset.template, ",[420,596,597],{"class":425},"...",[420,599,600],{"class":433},"(outcome ",[420,602,504],{"class":425},[420,604,513],{"class":456},[420,606,510],{"class":425},[420,608,609],{"class":429}," reasons",[420,611,612],{"class":433},"() ",[420,614,615],{"class":425},":",[420,617,618],{"class":433}," {}) });\n",[420,620,622],{"class":181,"line":621},10,[420,623,624],{"class":433},"});\n",[420,626,628],{"class":181,"line":627},11,[420,629,631],{"class":630},"sjfSM","\u002F\u002F trade-off: pageshow with persisted=false fires on the initial load too; the\n",[420,633,635],{"class":181,"line":634},12,[420,636,637],{"class":630},"\u002F\u002F navigation type check is what isolates back\u002Fforward misses.\n",[15,639,640],{},"Expected outcome: one row per back\u002Fforward navigation, classified as hit or miss.",[406,642,644],{"id":643},"_2-collect-and-flatten-notrestoredreasons","2. Collect and flatten notRestoredReasons",[411,646,648],{"className":413,"code":647,"language":415,"meta":416,"style":416},"function reasons() {\n  const nrr = performance.getEntriesByType('navigation')[0]?.notRestoredReasons;\n  if (!nrr) return {};\n  const out = [];\n  (function walk(node, depth) {\n    for (const r of node.reasons ?? []) out.push(`${depth ? 'frame:' : ''}${r.reason}`);\n    for (const child of node.children ?? []) walk(child, depth + 1);\n  })(nrr, 0);\n  return { reasons: [...new Set(out)].slice(0, 6) };\n}\n\u002F\u002F trade-off: cross-origin frames report a masked reason (\"masked\") for\n\u002F\u002F privacy, so third-party blockers may appear only as \"frame:masked\". Pair with\n\u002F\u002F DevTools tests to identify which embed it is.\n",[42,649,650,659,683,701,713,736,795,830,839,869,873,878,883],{"__ignoreMap":416},[420,651,652,654,656],{"class":181,"line":422},[420,653,426],{"class":425},[420,655,609],{"class":429},[420,657,658],{"class":433},"() {\n",[420,660,661,663,666,668,670,672,674,676,678,680],{"class":181,"line":444},[420,662,466],{"class":425},[420,664,665],{"class":469}," nrr",[420,667,473],{"class":425},[420,669,476],{"class":433},[420,671,479],{"class":429},[420,673,434],{"class":433},[420,675,484],{"class":456},[420,677,487],{"class":433},[420,679,66],{"class":469},[420,681,682],{"class":433},"]?.notRestoredReasons;\n",[420,684,685,687,690,693,696,698],{"class":181,"line":463},[420,686,447],{"class":425},[420,688,689],{"class":433}," (",[420,691,692],{"class":425},"!",[420,694,695],{"class":433},"nrr) ",[420,697,453],{"class":425},[420,699,700],{"class":433}," {};\n",[420,702,703,705,708,710],{"class":181,"line":495},[420,704,466],{"class":425},[420,706,707],{"class":469}," out",[420,709,473],{"class":425},[420,711,712],{"class":433}," [];\n",[420,714,715,718,720,723,725,728,731,734],{"class":181,"line":524},[420,716,717],{"class":433},"  (",[420,719,426],{"class":425},[420,721,722],{"class":429}," walk",[420,724,434],{"class":433},[420,726,727],{"class":437},"node",[420,729,730],{"class":433},", ",[420,732,733],{"class":437},"depth",[420,735,441],{"class":433},[420,737,738,741,743,746,749,752,755,758,761,764,766,769,771,773,776,778,781,784,786,789,792],{"class":181,"line":530},[420,739,740],{"class":425},"    for",[420,742,689],{"class":433},[420,744,745],{"class":425},"const",[420,747,748],{"class":469}," r",[420,750,751],{"class":425}," of",[420,753,754],{"class":433}," node.reasons ",[420,756,757],{"class":425},"??",[420,759,760],{"class":433}," []) out.",[420,762,763],{"class":429},"push",[420,765,434],{"class":433},[420,767,768],{"class":456},"`${",[420,770,733],{"class":433},[420,772,510],{"class":425},[420,774,775],{"class":456}," 'frame:'",[420,777,516],{"class":425},[420,779,780],{"class":456}," ''}${",[420,782,783],{"class":433},"r",[420,785,272],{"class":456},[420,787,788],{"class":433},"reason",[420,790,791],{"class":456},"}`",[420,793,794],{"class":433},");\n",[420,796,797,799,801,803,806,808,811,813,816,819,822,825,828],{"class":181,"line":555},[420,798,740],{"class":425},[420,800,689],{"class":433},[420,802,745],{"class":425},[420,804,805],{"class":469}," child",[420,807,751],{"class":425},[420,809,810],{"class":433}," node.children ",[420,812,757],{"class":425},[420,814,815],{"class":433}," []) ",[420,817,818],{"class":429},"walk",[420,820,821],{"class":433},"(child, depth ",[420,823,824],{"class":425},"+",[420,826,827],{"class":469}," 1",[420,829,794],{"class":433},[420,831,832,835,837],{"class":181,"line":570},[420,833,834],{"class":433},"  })(nrr, ",[420,836,66],{"class":469},[420,838,794],{"class":433},[420,840,841,843,846,849,852,855,858,860,862,864,866],{"class":181,"line":588},[420,842,498],{"class":425},[420,844,845],{"class":433}," { reasons: [",[420,847,848],{"class":425},"...new",[420,850,851],{"class":429}," Set",[420,853,854],{"class":433},"(out)].",[420,856,857],{"class":429},"slice",[420,859,434],{"class":433},[420,861,66],{"class":469},[420,863,730],{"class":433},[420,865,112],{"class":469},[420,867,868],{"class":433},") };\n",[420,870,871],{"class":181,"line":621},[420,872,527],{"class":433},[420,874,875],{"class":181,"line":627},[420,876,877],{"class":630},"\u002F\u002F trade-off: cross-origin frames report a masked reason (\"masked\") for\n",[420,879,880],{"class":181,"line":634},[420,881,882],{"class":630},"\u002F\u002F privacy, so third-party blockers may appear only as \"frame:masked\". Pair with\n",[420,884,886],{"class":181,"line":885},13,[420,887,888],{"class":630},"\u002F\u002F DevTools tests to identify which embed it is.\n",[15,890,891],{},"Expected outcome: a small set of reason strings per miss.",[406,893,895],{"id":894},"_3-report-the-hit-rate-per-template-and-browser","3. Report the hit rate per template and browser",[411,897,901],{"className":898,"code":899,"language":900,"meta":416,"style":416},"language-sql shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","SELECT template, browser,\n       COUNTIF(bf = 'hit') \u002F COUNT(*) AS hit_rate,\n       COUNT(*) AS bf_navigations\nFROM rum.bfcache WHERE ts > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)\nGROUP BY 1, 2 HAVING bf_navigations > 200 ORDER BY bf_navigations DESC;\n-- trade-off: Safari and Firefox do not expose reasons, but their hit rates are\n-- still meaningful; do not drop them from the hit-rate view.\n","sql",[42,902,903,908,913,918,923,928,933],{"__ignoreMap":416},[420,904,905],{"class":181,"line":422},[420,906,907],{},"SELECT template, browser,\n",[420,909,910],{"class":181,"line":444},[420,911,912],{},"       COUNTIF(bf = 'hit') \u002F COUNT(*) AS hit_rate,\n",[420,914,915],{"class":181,"line":463},[420,916,917],{},"       COUNT(*) AS bf_navigations\n",[420,919,920],{"class":181,"line":495},[420,921,922],{},"FROM rum.bfcache WHERE ts > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)\n",[420,924,925],{"class":181,"line":524},[420,926,927],{},"GROUP BY 1, 2 HAVING bf_navigations > 200 ORDER BY bf_navigations DESC;\n",[420,929,930],{"class":181,"line":530},[420,931,932],{},"-- trade-off: Safari and Firefox do not expose reasons, but their hit rates are\n",[420,934,935],{"class":181,"line":555},[420,936,937],{},"-- still meaningful; do not drop them from the hit-rate view.\n",[406,939,941],{"id":940},"_4-rank-reasons-by-impact","4. Rank reasons by impact",[15,943,944],{},"Count misses per reason per template, weighted by template traffic, and fix from the top.",[15,946,947],{},[53,948,60,951,60,954,60,957,60,959,60,962,60,964,60,971,60,978,60,983,60,987,60,992,60,996,60,1000,60,1004,60,1008,60,1012,60,1016,60],{"viewBox":949,"width":56,"role":57,"ariaLabel":950,"style":59},"0 0 760 194","Bar chart of bfcache hit rate for three templates before and after eligibility fixes.",[62,952],{"className":953,"x":66,"y":66,"width":56,"height":56,"fill":67},[65],[69,955,956],{},"Hit rate by template before and after fixes (Chromium)",[73,958,950],{},[62,960],{"x":95,"y":95,"width":96,"height":961,"rx":98,"fill":99,"stroke":91,"style":100},"192",[102,963,956],{"x":104,"y":105,"fill":91,"style":106},[102,965,970],{"x":966,"y":967,"fill":91,"style":968,"textAnchor":969},"153.6","70.0","font-size:13px","end","Search results before",[62,972],{"x":973,"y":109,"width":974,"height":975,"rx":976,"fill":130,"stroke":131,"style":977},"165.6","105.2","19","3","fill-opacity:0.7;stroke-opacity:0.9",[102,979,982],{"x":980,"y":967,"fill":91,"style":981},"276.7","font-size:12px;font-weight:600","18%",[102,984,986],{"x":966,"y":985,"fill":91,"style":968,"textAnchor":969},"101.0","Search results after",[62,988],{"x":973,"y":989,"width":990,"height":975,"rx":976,"fill":113,"stroke":113,"style":991},"87.0","502.4","fill-opacity:0.55;stroke-opacity:0.9",[102,993,995],{"x":994,"y":985,"fill":91,"style":981},"674.0","86%",[102,997,999],{"x":966,"y":998,"fill":91,"style":968,"textAnchor":969},"132.0","Product page before",[62,1001],{"x":973,"y":1002,"width":1003,"height":975,"rx":976,"fill":130,"stroke":131,"style":977},"118.0","181.1",[102,1005,1007],{"x":1006,"y":998,"fill":91,"style":981},"352.7","31%",[102,1009,1011],{"x":966,"y":1010,"fill":91,"style":968,"textAnchor":969},"163.0","Product page after",[62,1013],{"x":973,"y":1014,"width":1015,"height":975,"rx":976,"fill":113,"stroke":113,"style":991},"149.0","461.6",[102,1017,1019],{"x":1018,"y":1010,"fill":91,"style":981},"633.1","79%",[202,1021,1023],{"id":1022},"verification","Verification",[15,1025,1026],{},"Cross-check your hit rate with DevTools tests on the same templates: templates that pass in DevTools should show high field rates; low field rates on passing templates point to user-specific blockers (consent-dependent vendors, logged-in widgets). After each fix, the corresponding reason's share should fall and the hit rate rise within days.",[202,1028,1030],{"id":1029},"worked-example-a-travel-site-dashboard","Worked Example: A Travel Site Dashboard",[15,1032,1033,1034,1037,1038,1041,1042,1045,1046,1049],{},"A travel site added the classification beacon and found an overall Chromium hit rate of 27%. The top reasons were ",[42,1035,1036],{},"unload-listener"," (from an old affiliate tracking script) on 55% of misses, ",[42,1039,1040],{},"main-resource-has-cache-control-no-store"," on search results (22%), and ",[42,1043,1044],{},"masked"," frames (14%, later traced to a map embed). Fixing the first two over two sprints raised the hit rate to 71%; replacing the map embed with a static image and on-click loading took it to 83%. The dashboard became part of the weekly performance review, and a later regression — a new chat widget with an ",[42,1047,1048],{},"unload"," handler — was caught within two days.",[202,1051,1053],{"id":1052},"common-mistakes","Common Mistakes",[207,1055,1056,1062,1068,1074],{},[210,1057,1058,1061],{},[213,1059,1060],{},"Counting only Chromium."," Hit rates in Safari and Firefox matter too, even without reasons.",[210,1063,1064,1067],{},[213,1065,1066],{},"Reporting hit rate over all page views."," The denominator should be back\u002Fforward navigations, not all loads.",[210,1069,1070,1073],{},[213,1071,1072],{},"Ignoring SPA in-app navigations."," They are not bfcache navigations; exclude them from the metric.",[210,1075,1076,1079],{},[213,1077,1078],{},"Sending reasons on every page view."," Only misses need reasons; keep beacons small.",[202,1081,1083],{"id":1082},"edge-cases","Edge Cases",[15,1085,1086,1089,1090,1092,1093,1096],{},[213,1087,1088],{},"Pages restored multiple times."," A page can be restored, navigated away from and restored again; each ",[42,1091,121],{}," with ",[42,1094,1095],{},"persisted"," is a separate hit.",[15,1098,1099,1102],{},[213,1100,1101],{},"Prerendered pages."," Activation of a prerendered page is a different mechanism; classify it separately.",[15,1104,1105,1108,1109,1111],{},[213,1106,1107],{},"Iframes reporting their own navigations."," Only the top-level document's ",[42,1110,121],{}," should feed this metric.",[15,1113,1114,1117],{},[213,1115,1116],{},"Privacy."," Reason strings are browser-defined and not personal, but keep template names coarse and avoid sending URLs with query strings.",[202,1119,1121],{"id":1120},"connecting-hit-rate-to-user-outcomes","Connecting Hit Rate to User Outcomes",[15,1123,1124],{},"A hit rate on its own can feel abstract to stakeholders. Make it concrete by joining bfcache outcomes to engagement: for sessions that went back to a listing page, compare the number of subsequent product views, the bounce rate after the back navigation, and conversion, split by whether the return was restored or reloaded. On browse-heavy sites the difference is usually striking — restored returns lead to more onward exploration because the list is instantly there, scrolled to where the user left it. Present the metric alongside that comparison and the case for fixing the remaining blockers makes itself.",[15,1126,1127,1128,1131],{},"Also chart Core Web Vitals for back\u002Fforward navigations separately: restored navigations report near-zero LCP and should be excluded from LCP optimisation work, while reloads on back navigations often have ",[30,1129,1130],{},"worse"," LCP than first visits because the HTTP cache has been partly evicted. Both views help explain why the overall p75 moves when the hit rate changes.",[202,1133,1135],{"id":1134},"faq","FAQ",[1137,1138,1141,1145],"details",{"className":1139},[1140],"faq-item",[1142,1143,1144],"summary",{},"What is a good bfcache hit rate?",[15,1146,1147],{},"In Chromium, well-tuned sites reach 80–90% of back\u002Fforward navigations. Rates below 50% almost always have fixable blockers. Browser memory limits and evictions prevent 100%.",[1137,1149,1151,1154],{"className":1150},[1140],[1142,1152,1153],{},"Does the web-vitals library help?",[15,1155,1156,1157,1160],{},"Yes. It reports metrics for restored pages with ",[42,1158,1159],{},"navigationType: 'back-forward-cache'",", so you can see restored-page LCP and INP. It does not compute the hit rate or collect reasons; add the beacon described here.",[1137,1162,1164,1167],{"className":1163},[1140],[1142,1165,1166],{},"Should restored page views count in analytics?",[15,1168,1169,1170,1172],{},"Yes — they are real views. Many analytics tools count them via ",[42,1171,121],{},"; check yours, or your page view counts will drop when bfcache improves.",[1137,1174,1176,1179],{"className":1175},[1140],[1142,1177,1178],{},"Is notRestoredReasons available in all Chromium browsers?",[15,1180,1181],{},"It ships in Chromium-based browsers from version 123. Older versions return undefined; handle that gracefully.",[1137,1183,1185,1188],{"className":1184},[1140],[1142,1186,1187],{},"How do I attribute \"masked\" reasons?",[15,1189,1190],{},"Masked reasons come from cross-origin frames. Use DevTools' bfcache test on the template to see which frames block, or temporarily remove embeds in a test environment to isolate the culprit.",[1137,1192,1194,1197],{"className":1193},[1140],[1142,1195,1196],{},"Can I alert on the hit rate?",[15,1198,1199],{},"Yes, and it is worth it: a sudden drop usually means a new blocker shipped — a vendor update, a new widget, a header change. Alert on a sustained drop (for example ten percentage points over two days) per high-volume template, and include the top new reason in the alert so the owning team knows where to look.",[202,1201,1203],{"id":1202},"related","Related",[207,1205,1206,1213,1220],{},[210,1207,1208,1212],{},[19,1209,1211],{"href":1210},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Ffixing-bfcache-eligibility-blockers\u002F","Fixing bfcache eligibility blockers"," — acting on the ranked reasons.",[210,1214,1215,1219],{},[19,1216,1218],{"href":1217},"\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fcomputing-p75-from-raw-rum-beacons\u002F","Computing p75 from raw RUM beacons"," — handling restored navigations in percentiles.",[210,1221,1222,1226],{},[19,1223,1225],{"href":1224},"\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsegmenting-rum-by-device-and-connection\u002F","Segmenting RUM by device and connection"," — adding segments to the hit-rate view.",[1228,1229,1231],"script",{"type":1230},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Measure bfcache Hit Rate in Real-User Monitoring\",\n  \"description\": \"Build a field metric for back\u002Fforward cache restorations and miss reasons, and use it to prioritise and verify eligibility fixes.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Classify every page show\",\n      \"text\": \"Expected outcome: one row per back\u002Fforward navigation, classified as hit or miss.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Collect and flatten notRestoredReasons\",\n      \"text\": \"Expected outcome: a small set of reason strings per miss.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Report the hit rate per template and browser\",\n      \"text\": \"Report the hit rate per template and browser\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Rank reasons by impact\",\n      \"text\": \"Count misses per reason per template, weighted by template traffic, and fix from the top.\"\n    }\n  ]\n}\n",[1228,1233,1234],{"type":1230},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Measure bfcache Hit Rate in Real-User Monitoring\",\n  \"description\": \"Build a field metric for back\u002Fforward cache restorations and miss reasons, and use it to prioritise and verify eligibility fixes.\",\n  \"datePublished\": \"2026-10-06\",\n  \"dateModified\": \"2026-10-06\",\n  \"author\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"publisher\": {\n    \"@type\": \"Organization\",\n    \"name\": \"frontend-performance.com\"\n  },\n  \"mainEntityOfPage\": {\n    \"@type\": \"WebPage\",\n    \"@id\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Fmeasuring-bfcache-hit-rate-in-rum\u002F\"\n  }\n}\n",[1228,1236,1237],{"type":1230},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"BreadcrumbList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"name\": \"Home\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"name\": \"Advanced Caching Strategies & CDN Architecture\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"Back\u002FForward Cache (bfcache)\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Measuring bfcache Hit Rate in RUM\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Fmeasuring-bfcache-hit-rate-in-rum\u002F\"\n    }\n  ]\n}\n",[1239,1240,1241],"style",{},"html pre.shiki code .sPARh, html code.shiki .sPARh{--shiki-default:#A0111F;--shiki-dark:#FF9492;--shiki-light:#A0111F}html pre.shiki code .smZ65, html code.shiki .smZ65{--shiki-default:#622CBC;--shiki-dark:#DBB7FF;--shiki-light:#622CBC}html pre.shiki code .saISM, html code.shiki .saISM{--shiki-default:#0E1116;--shiki-dark:#F0F3F6;--shiki-light:#0E1116}html pre.shiki code .sQw3B, html code.shiki .sQw3B{--shiki-default:#702C00;--shiki-dark:#FFB757;--shiki-light:#702C00}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}html pre.shiki code .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}",{"title":416,"searchDepth":444,"depth":444,"links":1243},[1244,1245,1246,1252,1253,1254,1255,1256,1257,1258],{"id":204,"depth":444,"text":205},{"id":249,"depth":444,"text":250},{"id":403,"depth":444,"text":404,"children":1247},[1248,1249,1250,1251],{"id":408,"depth":463,"text":409},{"id":643,"depth":463,"text":644},{"id":894,"depth":463,"text":895},{"id":940,"depth":463,"text":941},{"id":1022,"depth":444,"text":1023},{"id":1029,"depth":444,"text":1030},{"id":1052,"depth":444,"text":1053},{"id":1082,"depth":444,"text":1083},{"id":1120,"depth":444,"text":1121},{"id":1134,"depth":444,"text":1135},{"id":1202,"depth":444,"text":1203},"Build a field metric for back\u002Fforward cache restorations and miss reasons, and use it to prioritise and verify eligibility fixes.","md",{"slug":1262,"type":1263,"breadcrumb":1264,"datePublished":1271,"dateModified":1271},"measuring-bfcache-hit-rate-in-rum","article",[1265,1267,1268,1269],{"name":1266,"url":260},"Home",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1270},"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Fmeasuring-bfcache-hit-rate-in-rum\u002F","2026-10-06",true,"\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Fmeasuring-bfcache-hit-rate-in-rum",{"title":1275,"description":1276},"Measuring bfcache Hit Rate in Real-User Monitoring","Track what share of back\u002Fforward navigations are restored from bfcache, collect notRestoredReasons, and segment by template and browser to prioritise fixes.","advanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Fmeasuring-bfcache-hit-rate-in-rum\u002Findex","HkUDCz3dtIPHDVgELQk9PuuXiv6Sq5KrkDDQilawMHQ",[1280,1284],{"title":1281,"path":1282,"stem":1283,"children":-1},"Fixing bfcache Eligibility Blockers","\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Ffixing-bfcache-eligibility-blockers","advanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Ffixing-bfcache-eligibility-blockers\u002Findex",{"title":1285,"path":1286,"stem":1287,"children":-1},"Replacing unload Handlers for bfcache","\u002Fadvanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Freplacing-unload-handlers-for-bfcache","advanced-caching-strategies-cdn-architecture\u002Fback-forward-cache-bfcache\u002Freplacing-unload-handlers-for-bfcache\u002Findex",1791308072866]