[{"data":1,"prerenderedAt":1083},["ShallowReactive",2],{"content:\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsampling-rum-data-without-biasing-p75":3,"surroundings:\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsampling-rum-data-without-biasing-p75":1074},{"id":4,"title":5,"body":6,"description":1054,"extension":1055,"meta":1056,"navigation":1067,"path":1068,"seo":1069,"stem":1072,"__hash__":1073},"content\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsampling-rum-data-without-biasing-p75\u002Findex.md","Sampling RUM Data Without Biasing p75",{"type":7,"value":8,"toc":1039},"minimark",[9,14,29,37,150,155,189,193,199,205,211,225,311,315,320,323,566,569,573,612,615,619,622,734,737,741,744,801,804,914,918,921,925,928,932,958,962,979,988,997,1001,1024,1029,1032,1035],[10,11,13],"h1",{"id":12},"how-to-sample-rum-data-without-biasing-your-p75","How to Sample RUM Data Without Biasing Your p75",[15,16,17,18,23,24,28],"p",{},"This guide sits within ",[19,20,22],"a",{"href":21},"\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002F","RUM Beacons & Field Data Collection"," in ",[19,25,27],{"href":26},"\u002Fcore-web-vitals-measurement\u002F","Core Web Vitals & Measurement",". Real-user monitoring at scale is expensive: a site with 50 million page views a month sends 50 million beacons, each a few kilobytes, plus the storage and query cost of keeping them. Sampling is the obvious answer, and done carelessly it quietly changes the number you are trying to measure.",[15,30,31,32,36],{},"The p75 is a statistic of the ",[33,34,35],"em",{},"distribution",". Sampling preserves it only if the sampled visits are representative — if every kind of visit (slow device, fast device, first view, deep session) is equally likely to be kept. Common sampling shortcuts violate that: sampling by page view rather than by session, sampling only after a metric is known, sampling at different rates by page, or dropping beacons that fail to send on slow connections. Each skews the distribution, and the p75 moves with it.",[15,38,39],{},[40,41,47,48,47,55,47,59,47,62,47,71,47,77,47,86,47,92,47,97,47,102,47,105,47,108,47,111,47,114,47,117,47,120,47,125,47,129,47,131,47,135,47,137,47,140,47,142,47,145,47,147,47],"svg",{"viewBox":42,"width":43,"role":44,"ariaLabel":45,"style":46},"0 0 760 228","100%","img","Comparison of sampling practices that skew the 75th percentile with practices that preserve it.","height:auto;max-width:760px;display:block;margin:1.75rem auto;font-family:inherit;color:var(--fp-svg-ink)"," ",[49,50],"rect",{"className":51,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],"svg-canvas","0","#ffffff",[56,57,58],"title",{},"Biased vs unbiased sampling",[60,61,45],"desc",{},[49,63],{"x":64,"y":64,"width":65,"height":66,"rx":67,"fill":68,"stroke":69,"style":70},"1","758","226","10","none","currentColor","stroke-opacity:0.18",[72,73,58],"text",{"x":74,"y":75,"fill":69,"style":76},"28.0","34.0","font-size:16px;font-weight:700",[49,78],{"x":74,"y":79,"width":80,"height":81,"rx":82,"fill":83,"stroke":84,"style":85},"56.0","340.0","150.0","6","#ffc300","#b8860b","fill-opacity:0.24;stroke-opacity:0.9",[72,87,91],{"x":88,"y":89,"fill":69,"style":90},"42.0","82.0","font-size:14px;font-weight:700","Skews the p75",[72,93,96],{"x":88,"y":94,"fill":69,"style":95},"108.0","font-size:12.5px;font-weight:700","•",[72,98,101],{"x":79,"y":94,"fill":69,"style":99,"textAnchor":100},"font-size:12.5px","start","Random per page view (sessions split)",[72,103,96],{"x":88,"y":104,"fill":69,"style":95},"132.0",[72,106,107],{"x":79,"y":104,"fill":69,"style":99,"textAnchor":100},"Decide after seeing the metric value",[72,109,96],{"x":88,"y":110,"fill":69,"style":95},"156.0",[72,112,113],{"x":79,"y":110,"fill":69,"style":99,"textAnchor":100},"Different rates per template, unweighted",[72,115,96],{"x":88,"y":116,"fill":69,"style":95},"180.0",[72,118,119],{"x":79,"y":116,"fill":69,"style":99,"textAnchor":100},"Beacons lost on unload not counted",[49,121],{"x":122,"y":79,"width":80,"height":81,"rx":82,"fill":123,"stroke":123,"style":124},"392.0","#0466c8","fill-opacity:0.14;stroke-opacity:0.9",[72,126,128],{"x":127,"y":89,"fill":69,"style":90},"406.0","Preserves the p75",[72,130,96],{"x":127,"y":94,"fill":69,"style":95},[72,132,134],{"x":133,"y":94,"fill":69,"style":99,"textAnchor":100},"420.0","Deterministic per session id",[72,136,96],{"x":127,"y":104,"fill":69,"style":95},[72,138,139],{"x":133,"y":104,"fill":69,"style":99,"textAnchor":100},"Decide before any metric is observed",[72,141,96],{"x":127,"y":110,"fill":69,"style":95},[72,143,144],{"x":133,"y":110,"fill":69,"style":99,"textAnchor":100},"Per-template rates with weights stored",[72,146,96],{"x":127,"y":116,"fill":69,"style":95},[72,148,149],{"x":133,"y":116,"fill":69,"style":99,"textAnchor":100},"Delivery measured and corrected",[151,152,154],"h2",{"id":153},"rapid-diagnosis","Rapid Diagnosis",[156,157,158,166,177,183],"ul",{},[159,160,161,165],"li",{},[162,163,164],"strong",{},"Compare sampled and unsampled p75."," Run 100% collection for a day on a subset of traffic and compare with the sampled pipeline. A gap of more than a few percent indicates bias.",[159,167,168,171,172,176],{},[162,169,170],{},"Check where the sampling decision is made."," If it happens inside a metric callback (",[173,174,175],"code",{},"onLCP(v => Math.random() \u003C 0.1 && send(v))","), sessions contribute some metrics and not others — inconsistent.",[159,178,179,182],{},[162,180,181],{},"Check per-template rates."," If product pages are sampled at 10% and checkout at 100%, an unweighted origin-level p75 over-represents checkout.",[159,184,185,188],{},[162,186,187],{},"Check delivery rates by device."," Compare beacons received against page views from server logs, by device class. Low-end devices often lose more beacons.",[151,190,192],{"id":191},"root-cause-analysis","Root Cause Analysis",[15,194,195,198],{},[162,196,197],{},"1. Page-view sampling breaks session-level metrics."," INP and CLS are per page visit, but analysis often joins visits into sessions. Random per-page-view sampling keeps fragments of sessions, distorting anything computed across them.",[15,200,201,204],{},[162,202,203],{},"2. Value-dependent sampling."," Deciding to send based on the value (\"only send slow LCPs to save cost\") is no longer a sample of the distribution. Any percentile computed from it is meaningless.",[15,206,207,210],{},[162,208,209],{},"3. Unweighted stratified sampling."," Sampling different segments at different rates is efficient, but every aggregate must weight each beacon by the inverse of its sampling rate.",[15,212,213,216,217,220,221,224],{},[162,214,215],{},"4. Survivorship bias in delivery."," Beacons sent late (on ",[173,218,219],{},"pagehide"," or ",[173,222,223],{},"visibilitychange",") are lost more often on slow, low-memory devices and poor networks — exactly the visits that sit above p75.",[15,226,227],{},[40,228,47,231,47,234,47,237,47,239,47,242,47,244,47,251,47,258,47,263,47,267,47,272,47,276,47,279,47,284,47,288,47,292,47,296,47,300,47,304,47,307,47],{"viewBox":229,"width":43,"role":44,"ariaLabel":230,"style":46},"0 0 760 225","Bar chart of mobile p75 LCP computed from full data and from four sampling schemes, showing which schemes bias the result.",[49,232],{"className":233,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],[56,235,236],{},"p75 LCP under different sampling schemes (same traffic)",[60,238,230],{},[49,240],{"x":64,"y":64,"width":65,"height":241,"rx":67,"fill":68,"stroke":69,"style":70},"223",[72,243,236],{"x":74,"y":75,"fill":69,"style":76},[72,245,250],{"x":246,"y":247,"fill":69,"style":248,"textAnchor":249},"205.5","70.0","font-size:13px","end","Full data (truth)",[49,252],{"x":253,"y":79,"width":254,"height":255,"rx":256,"fill":69,"stroke":69,"style":257},"217.5","374.1","19","3","fill-opacity:0.7;stroke-opacity:0.4",[72,259,262],{"x":260,"y":247,"fill":69,"style":261},"597.6","font-size:12px;font-weight:600","2840ms",[72,264,266],{"x":246,"y":265,"fill":69,"style":248,"textAnchor":249},"101.0","Session-based 10%",[49,268],{"x":253,"y":269,"width":270,"height":255,"rx":256,"fill":123,"stroke":123,"style":271},"87.0","372.7","fill-opacity:0.55;stroke-opacity:0.9",[72,273,275],{"x":274,"y":265,"fill":69,"style":261},"596.3","2830ms",[72,277,278],{"x":246,"y":104,"fill":69,"style":248,"textAnchor":249},"Per-template rates unweighted",[49,280],{"x":253,"y":281,"width":282,"height":255,"rx":256,"fill":83,"stroke":84,"style":283},"118.0","343.8","fill-opacity:0.7;stroke-opacity:0.9",[72,285,287],{"x":286,"y":104,"fill":69,"style":261},"567.3","2610ms",[72,289,291],{"x":246,"y":290,"fill":69,"style":248,"textAnchor":249},"163.0","Send only if value over 2s",[49,293],{"x":253,"y":294,"width":295,"height":255,"rx":256,"fill":83,"stroke":84,"style":283},"149.0","450.5",[72,297,299],{"x":298,"y":290,"fill":69,"style":261},"674.0","3420ms",[72,301,303],{"x":246,"y":302,"fill":69,"style":248,"textAnchor":249},"194.0","Unload-only beacons",[49,305],{"x":253,"y":116,"width":306,"height":255,"rx":256,"fill":83,"stroke":84,"style":283},"335.9",[72,308,310],{"x":309,"y":302,"fill":69,"style":261},"559.4","2550ms",[151,312,314],{"id":313},"step-by-step-resolution","Step-by-Step Resolution",[316,317,319],"h3",{"id":318},"_1-sample-by-session-deterministically-before-measuring","1. Sample by session, deterministically, before measuring",[15,321,322],{},"Derive the sampling decision from a stable session identifier, once, at page start. Every page view in the session gets the same decision; every metric in the page view is sent or not as a unit.",[324,325,330],"pre",{"className":326,"code":327,"language":328,"meta":329,"style":329},"language-javascript shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","\u002F\u002F Deterministic session sampling: the same session id always gets the same answer.\nfunction sampled(sessionId, rate) {\n  let h = 2166136261;                                   \u002F\u002F FNV-1a hash\n  for (let i = 0; i \u003C sessionId.length; i++) h = Math.imul(h ^ sessionId.charCodeAt(i), 16777619);\n  return (h >>> 0) \u002F 2 ** 32 \u003C rate;\n}\nconst RATE = 0.1;\nexport const inSample = sampled(getSessionId(), RATE);\n\u002F\u002F trade-off: session-level sampling gives fewer independent units than page-\n\u002F\u002F view sampling at the same rate, so confidence intervals are wider for small\n\u002F\u002F segments. Raise the rate for low-traffic templates (and weight, step 2).\n","javascript","",[173,331,332,341,369,391,460,495,501,519,548,554,560],{"__ignoreMap":329},[333,334,337],"span",{"class":335,"line":336},"line",1,[333,338,340],{"class":339},"sjfSM","\u002F\u002F Deterministic session sampling: the same session id always gets the same answer.\n",[333,342,344,348,352,356,360,363,366],{"class":335,"line":343},2,[333,345,347],{"class":346},"sPARh","function",[333,349,351],{"class":350},"smZ65"," sampled",[333,353,355],{"class":354},"saISM","(",[333,357,359],{"class":358},"sQw3B","sessionId",[333,361,362],{"class":354},", ",[333,364,365],{"class":358},"rate",[333,367,368],{"class":354},") {\n",[333,370,372,375,378,381,385,388],{"class":335,"line":371},3,[333,373,374],{"class":346},"  let",[333,376,377],{"class":354}," h ",[333,379,380],{"class":346},"=",[333,382,384],{"class":383},"sPXB4"," 2166136261",[333,386,387],{"class":354},";                                   ",[333,389,390],{"class":339},"\u002F\u002F FNV-1a hash\n",[333,392,394,397,400,403,406,408,411,414,417,420,423,426,429,432,434,437,440,443,446,448,451,454,457],{"class":335,"line":393},4,[333,395,396],{"class":346},"  for",[333,398,399],{"class":354}," (",[333,401,402],{"class":346},"let",[333,404,405],{"class":354}," i ",[333,407,380],{"class":346},[333,409,410],{"class":383}," 0",[333,412,413],{"class":354},"; i ",[333,415,416],{"class":346},"\u003C",[333,418,419],{"class":354}," sessionId.",[333,421,422],{"class":383},"length",[333,424,425],{"class":354},"; i",[333,427,428],{"class":346},"++",[333,430,431],{"class":354},") h ",[333,433,380],{"class":346},[333,435,436],{"class":354}," Math.",[333,438,439],{"class":350},"imul",[333,441,442],{"class":354},"(h ",[333,444,445],{"class":346},"^",[333,447,419],{"class":354},[333,449,450],{"class":350},"charCodeAt",[333,452,453],{"class":354},"(i), ",[333,455,456],{"class":383},"16777619",[333,458,459],{"class":354},");\n",[333,461,463,466,469,472,474,477,480,483,486,489,492],{"class":335,"line":462},5,[333,464,465],{"class":346},"  return",[333,467,468],{"class":354}," (h ",[333,470,471],{"class":346},">>>",[333,473,410],{"class":383},[333,475,476],{"class":354},") ",[333,478,479],{"class":346},"\u002F",[333,481,482],{"class":383}," 2",[333,484,485],{"class":346}," **",[333,487,488],{"class":383}," 32",[333,490,491],{"class":346}," \u003C",[333,493,494],{"class":354}," rate;\n",[333,496,498],{"class":335,"line":497},6,[333,499,500],{"class":354},"}\n",[333,502,504,507,510,513,516],{"class":335,"line":503},7,[333,505,506],{"class":346},"const",[333,508,509],{"class":383}," RATE",[333,511,512],{"class":346}," =",[333,514,515],{"class":383}," 0.1",[333,517,518],{"class":354},";\n",[333,520,522,525,528,531,533,535,537,540,543,546],{"class":335,"line":521},8,[333,523,524],{"class":346},"export",[333,526,527],{"class":346}," const",[333,529,530],{"class":383}," inSample",[333,532,512],{"class":346},[333,534,351],{"class":350},[333,536,355],{"class":354},[333,538,539],{"class":350},"getSessionId",[333,541,542],{"class":354},"(), ",[333,544,545],{"class":383},"RATE",[333,547,459],{"class":354},[333,549,551],{"class":335,"line":550},9,[333,552,553],{"class":339},"\u002F\u002F trade-off: session-level sampling gives fewer independent units than page-\n",[333,555,557],{"class":335,"line":556},10,[333,558,559],{"class":339},"\u002F\u002F view sampling at the same rate, so confidence intervals are wider for small\n",[333,561,563],{"class":335,"line":562},11,[333,564,565],{"class":339},"\u002F\u002F segments. Raise the rate for low-traffic templates (and weight, step 2).\n",[15,567,568],{},"Expected outcome: sampled p75 matches full-data p75 within normal statistical noise.",[316,570,572],{"id":571},"_2-store-the-sampling-rate-on-every-beacon-and-weight-aggregates","2. Store the sampling rate on every beacon and weight aggregates",[324,574,576],{"className":326,"code":575,"language":328,"meta":329,"style":329},"send({ ...metrics, sampleRate: RATE, template });\n\u002F\u002F SQL: weighted percentile — each row stands for 1\u002FsampleRate page views.\n\u002F\u002F trade-off: most warehouses lack a native weighted percentile; approximate by\n\u002F\u002F expanding weights into histogram bins (step 4) rather than duplicating rows.\n",[173,577,578,597,602,607],{"__ignoreMap":329},[333,579,580,583,586,589,592,594],{"class":335,"line":336},[333,581,582],{"class":350},"send",[333,584,585],{"class":354},"({ ",[333,587,588],{"class":346},"...",[333,590,591],{"class":354},"metrics, sampleRate: ",[333,593,545],{"class":383},[333,595,596],{"class":354},", template });\n",[333,598,599],{"class":335,"line":343},[333,600,601],{"class":339},"\u002F\u002F SQL: weighted percentile — each row stands for 1\u002FsampleRate page views.\n",[333,603,604],{"class":335,"line":371},[333,605,606],{"class":339},"\u002F\u002F trade-off: most warehouses lack a native weighted percentile; approximate by\n",[333,608,609],{"class":335,"line":393},[333,610,611],{"class":339},"\u002F\u002F expanding weights into histogram bins (step 4) rather than duplicating rows.\n",[15,613,614],{},"Expected outcome: you can sample rare templates at 100% and common ones at 5% while keeping origin-level aggregates correct.",[316,616,618],{"id":617},"_3-measure-delivery-and-send-early-where-possible","3. Measure delivery and send early where possible",[15,620,621],{},"Send what you know as soon as it is final, rather than everything on page hide. LCP is final after the first interaction; CLS and INP must wait for hide. Track delivery rate per segment by comparing beacons with server-side page views.",[324,623,625],{"className":326,"code":624,"language":328,"meta":329,"style":329},"import { onLCP, onCLS, onINP } from 'web-vitals';\nonLCP((m) => inSample && sendNow(m));                     \u002F\u002F final early — send immediately\nonCLS((m) => inSample && queueForHide(m));\nonINP((m) => inSample && queueForHide(m));\n\u002F\u002F trade-off: sending LCP separately costs an extra request per page view. On\n\u002F\u002F very high-traffic sites, batch it with the hide beacon but also flush on\n\u002F\u002F a 10s timer so long visits do not hold it until unload.\n",[173,626,627,644,675,698,719,724,729],{"__ignoreMap":329},[333,628,629,632,635,638,642],{"class":335,"line":336},[333,630,631],{"class":346},"import",[333,633,634],{"class":354}," { onLCP, onCLS, onINP } ",[333,636,637],{"class":346},"from",[333,639,641],{"class":640},"sZ8jY"," 'web-vitals'",[333,643,518],{"class":354},[333,645,646,649,652,655,657,660,663,666,669,672],{"class":335,"line":343},[333,647,648],{"class":350},"onLCP",[333,650,651],{"class":354},"((",[333,653,654],{"class":358},"m",[333,656,476],{"class":354},[333,658,659],{"class":346},"=>",[333,661,662],{"class":354}," inSample ",[333,664,665],{"class":346},"&&",[333,667,668],{"class":350}," sendNow",[333,670,671],{"class":354},"(m));                     ",[333,673,674],{"class":339},"\u002F\u002F final early — send immediately\n",[333,676,677,680,682,684,686,688,690,692,695],{"class":335,"line":371},[333,678,679],{"class":350},"onCLS",[333,681,651],{"class":354},[333,683,654],{"class":358},[333,685,476],{"class":354},[333,687,659],{"class":346},[333,689,662],{"class":354},[333,691,665],{"class":346},[333,693,694],{"class":350}," queueForHide",[333,696,697],{"class":354},"(m));\n",[333,699,700,703,705,707,709,711,713,715,717],{"class":335,"line":393},[333,701,702],{"class":350},"onINP",[333,704,651],{"class":354},[333,706,654],{"class":358},[333,708,476],{"class":354},[333,710,659],{"class":346},[333,712,662],{"class":354},[333,714,665],{"class":346},[333,716,694],{"class":350},[333,718,697],{"class":354},[333,720,721],{"class":335,"line":462},[333,722,723],{"class":339},"\u002F\u002F trade-off: sending LCP separately costs an extra request per page view. On\n",[333,725,726],{"class":335,"line":497},[333,727,728],{"class":339},"\u002F\u002F very high-traffic sites, batch it with the hide beacon but also flush on\n",[333,730,731],{"class":335,"line":503},[333,732,733],{"class":339},"\u002F\u002F a 10s timer so long visits do not hold it until unload.\n",[15,735,736],{},"Expected outcome: fewer lost LCP values on slow devices; measured delivery gaps you can correct for or at least report.",[316,738,740],{"id":739},"_4-aggregate-with-histograms-for-weighted-percentiles","4. Aggregate with histograms for weighted percentiles",[15,742,743],{},"Bucket values into fixed bins (for example, 100ms bins up to 10s for LCP), sum weights per bin, and read the percentile from the cumulative weighted histogram. This scales to billions of beacons and handles weights naturally.",[324,745,749],{"className":746,"code":747,"language":748,"meta":329,"style":329},"language-sql shiki shiki-themes github-light-high-contrast github-dark-high-contrast github-light-high-contrast","WITH bins AS (\n  SELECT template, LEAST(FLOOR(lcp \u002F 100) * 100, 10000) AS bin, SUM(1 \u002F sample_rate) AS w\n  FROM rum.beacons WHERE device = 'mobile' GROUP BY 1, 2\n), cum AS (\n  SELECT template, bin, SUM(w) OVER (PARTITION BY template ORDER BY bin) \u002F SUM(w) OVER (PARTITION BY template) AS cdf\n  FROM bins\n)\nSELECT template, MIN(bin) AS p75_lcp FROM cum WHERE cdf >= 0.75 GROUP BY template;\n-- trade-off: 100ms bins cap precision at ±50ms. Use finer bins near the\n-- threshold if you need to know whether p75 is 2480ms or 2520ms.\n","sql",[173,750,751,756,761,766,771,776,781,786,791,796],{"__ignoreMap":329},[333,752,753],{"class":335,"line":336},[333,754,755],{},"WITH bins AS (\n",[333,757,758],{"class":335,"line":343},[333,759,760],{},"  SELECT template, LEAST(FLOOR(lcp \u002F 100) * 100, 10000) AS bin, SUM(1 \u002F sample_rate) AS w\n",[333,762,763],{"class":335,"line":371},[333,764,765],{},"  FROM rum.beacons WHERE device = 'mobile' GROUP BY 1, 2\n",[333,767,768],{"class":335,"line":393},[333,769,770],{},"), cum AS (\n",[333,772,773],{"class":335,"line":462},[333,774,775],{},"  SELECT template, bin, SUM(w) OVER (PARTITION BY template ORDER BY bin) \u002F SUM(w) OVER (PARTITION BY template) AS cdf\n",[333,777,778],{"class":335,"line":497},[333,779,780],{},"  FROM bins\n",[333,782,783],{"class":335,"line":503},[333,784,785],{},")\n",[333,787,788],{"class":335,"line":521},[333,789,790],{},"SELECT template, MIN(bin) AS p75_lcp FROM cum WHERE cdf >= 0.75 GROUP BY template;\n",[333,792,793],{"class":335,"line":550},[333,794,795],{},"-- trade-off: 100ms bins cap precision at ±50ms. Use finer bins near the\n",[333,797,798],{"class":335,"line":556},[333,799,800],{},"-- threshold if you need to know whether p75 is 2480ms or 2520ms.\n",[15,802,803],{},"Expected outcome: correct weighted p75 per template and per origin at a fraction of the storage cost.",[15,805,806],{},[40,807,47,810,47,813,47,816,47,818,47,821,47,823,47,828,47,834,47,839,47,842,47,846,47,850,47,853,47,857,47,861,47,864,47,868,47,872,47,879,47,883,47,887,47,892,47,895,47,898,47,901,47,904,47,907,47,910,47],{"viewBox":808,"width":43,"role":44,"ariaLabel":809,"style":46},"0 0 760 318","Four stages of an unbiased RUM sampling pipeline, from the session-level decision to weighted percentile queries.",[49,811],{"className":812,"x":53,"y":53,"width":43,"height":43,"fill":54},[52],[56,814,815],{},"A sampling pipeline that keeps p75 honest",[60,817,809],{},[49,819],{"x":64,"y":64,"width":65,"height":820,"rx":67,"fill":68,"stroke":69,"style":70},"316",[72,822,815],{"x":74,"y":75,"fill":69,"style":76},[49,824],{"x":825,"y":79,"width":826,"height":827,"rx":82,"fill":123,"stroke":123,"style":124},"72.0","660.0","51.0",[72,829,833],{"x":830,"y":831,"fill":69,"style":832,"textAnchor":100},"86.0","77.0","font-size:13px;font-weight:700","Decide per session at page start",[72,835,838],{"x":830,"y":836,"fill":69,"style":837,"textAnchor":100},"94.0","font-size:12px","Hash of a stable session id against the rate",[49,840],{"x":825,"y":841,"width":826,"height":827,"rx":82,"fill":123,"stroke":123,"style":124},"119.0",[72,843,845],{"x":830,"y":844,"fill":69,"style":832,"textAnchor":100},"140.0","Tag every beacon with its rate",[72,847,849],{"x":830,"y":848,"fill":69,"style":837,"textAnchor":100},"157.0","sampleRate travels with the data, per template if rates differ",[49,851],{"x":825,"y":852,"width":826,"height":827,"rx":82,"fill":123,"stroke":123,"style":124},"182.0",[72,854,856],{"x":830,"y":855,"fill":69,"style":832,"textAnchor":100},"203.0","Send final values early where possible",[72,858,860],{"x":830,"y":859,"fill":69,"style":837,"textAnchor":100},"220.0","LCP immediately; CLS and INP on hide",[49,862],{"x":825,"y":863,"width":826,"height":827,"rx":82,"fill":123,"stroke":123,"style":124},"245.0",[72,865,867],{"x":830,"y":866,"fill":69,"style":832,"textAnchor":100},"266.0","Aggregate with weighted histograms",[72,869,871],{"x":830,"y":870,"fill":69,"style":837,"textAnchor":100},"283.0","Each beacon counts as 1\u002FsampleRate page views",[335,873],{"x1":874,"y1":875,"x2":874,"y2":876,"stroke":69,"strokeWidth":877,"style":878},"43.0","95.5","130.5","1.5","stroke-opacity:0.3",[335,880],{"x1":874,"y1":881,"x2":874,"y2":882,"stroke":69,"strokeWidth":877,"style":878},"158.5","193.5",[335,884],{"x1":874,"y1":885,"x2":874,"y2":886,"stroke":69,"strokeWidth":877,"style":878},"221.5","256.5",[888,889],"circle",{"cx":874,"cy":890,"r":891,"fill":123},"81.5","13",[72,893,64],{"x":874,"y":830,"fill":54,"style":832,"textAnchor":894},"middle",[888,896],{"cx":874,"cy":897,"r":891,"fill":123},"144.5",[72,899,900],{"x":874,"y":294,"fill":54,"style":832,"textAnchor":894},"2",[888,902],{"cx":874,"cy":903,"r":891,"fill":123},"207.5",[72,905,256],{"x":874,"y":906,"fill":54,"style":832,"textAnchor":894},"212.0",[888,908],{"cx":874,"cy":909,"r":891,"fill":123},"270.5",[72,911,913],{"x":874,"y":912,"fill":54,"style":832,"textAnchor":894},"275.0","4",[151,915,917],{"id":916},"verification","Verification",[15,919,920],{},"Run an A\u002FA comparison: for one week, collect a 100% sample on 5% of sessions alongside your production sampling. Compute p75 for LCP, INP and CLS per template from both. The difference should fall within the confidence interval for the sampled data; if it does not, check sampling decision placement and weighting. Repeat whenever you change rates.",[151,922,924],{"id":923},"how-much-sampling-is-safe","How Much Sampling Is Safe?",[15,926,927],{},"The precision of a percentile estimate depends on the number of samples, not the fraction of traffic. As a rule of thumb, a few thousand page views per segment per period gives a p75 stable to within a few percent; below a few hundred, percentiles swing noticeably from day to day. Work backwards: decide which segments you need to report (template × device × week, say), estimate their traffic, and choose the lowest rate that keeps each above a few thousand samples. Where a segment is too small at any affordable rate, sample it at 100% and rely on the weights to keep origin-level numbers honest. Report sample counts alongside every percentile so readers can judge reliability.",[151,929,931],{"id":930},"common-sampling-mistakes-in-practice","Common Sampling Mistakes in Practice",[156,933,934,940,946,952],{},[159,935,936,939],{},[162,937,938],{},"Changing the rate mid-period without recording it."," A dashboard computing a 28-day p75 across a rate change from 10% to 2% is fine only if every beacon carries its own rate and aggregates are weighted.",[159,941,942,945],{},[162,943,944],{},"Sampling in the tag manager."," A sampling trigger configured in a tag manager often evaluates per page view and after other tags have run, combining both of the worst choices.",[159,947,948,951],{},[162,949,950],{},"Different rates per browser."," Sampling Safari at a lower rate because \"it has fewer metrics\" skews any cross-browser comparison unless weighted.",[159,953,954,957],{},[162,955,956],{},"Dropping beacons server-side under load."," Ingestion pipelines that shed load randomly during traffic spikes under-represent peak periods — when pages are often slowest. Prefer client-side sampling decided in advance.",[151,959,961],{"id":960},"faq","FAQ",[963,964,967,971],"details",{"className":965},[966],"faq-item",[968,969,970],"summary",{},"Is CrUX itself sampled?",[15,972,973,974,978],{},"CrUX collects from opted-in Chrome users only, which is a different kind of selection — it is not a random sample of all your visitors, and it excludes other browsers entirely. That is one reason ",[19,975,977],{"href":976},"\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fcrux-vs-your-own-rum-why-the-numbers-differ\u002F","CrUX and your own RUM differ",". Your own sampling should aim to represent your traffic, not to mimic CrUX.",[963,980,982,985],{"className":981},[966],[968,983,984],{},"Can I sample attribution data at a lower rate than metrics?",[15,986,987],{},"Yes, if the attribution sample is itself drawn session-deterministically from the metric sample — for example, a second hash threshold. Attribution then describes a representative subset of the same visits. Never select attribution sessions based on whether their metric was bad.",[963,989,991,994],{"className":990},[966],[968,992,993],{},"What about bots and synthetic traffic?",[15,995,996],{},"Exclude them before sampling, using user-agent and behavioural filters, so they neither consume sample budget nor distort percentiles. Synthetic monitoring traffic from your own tools should be tagged and excluded explicitly; it is usually fast and pulls p75 down.",[151,998,1000],{"id":999},"related","Related",[156,1002,1003,1010,1017],{},[159,1004,1005,1009],{},[19,1006,1008],{"href":1007},"\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fcomputing-p75-from-raw-rum-beacons\u002F","Computing p75 from raw RUM beacons"," — the aggregation maths in detail.",[159,1011,1012,1016],{},[19,1013,1015],{"href":1014},"\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsending-web-vitals-with-sendbeacon-on-visibility-change\u002F","Sending web vitals with sendBeacon on visibility change"," — maximising delivery.",[159,1018,1019,1023],{},[19,1020,1022],{"href":1021},"\u002Fcore-web-vitals-measurement\u002Flong-animation-frames-api\u002Fsending-loaf-data-in-rum-beacons\u002F","Sending LoAF data in RUM beacons"," — keeping attribution payloads small.",[1025,1026,1028],"script",{"type":1027},"application\u002Fld+json","\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"HowTo\",\n  \"name\": \"How to Sample RUM Data Without Biasing Your p75\",\n  \"description\": \"How to reduce RUM volume with session-level, deterministic sampling that keeps the 75th percentile honest across segments.\",\n  \"step\": [\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 1,\n      \"name\": \"Sample by session, deterministically, before measuring\",\n      \"text\": \"Derive the sampling decision from a stable session identifier, once, at page start.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 2,\n      \"name\": \"Store the sampling rate on every beacon and weight aggregates\",\n      \"text\": \"Expected outcome: you can sample rare templates at 100% and common ones at 5% while keeping origin-level aggregates correct.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 3,\n      \"name\": \"Measure delivery and send early where possible\",\n      \"text\": \"Send what you know as soon as it is final, rather than everything on page hide.\"\n    },\n    {\n      \"@type\": \"HowToStep\",\n      \"position\": 4,\n      \"name\": \"Aggregate with histograms for weighted percentiles\",\n      \"text\": \"Bucket values into fixed bins (for example, 100ms bins up to 10s for LCP), sum weights per bin, and read the percentile from the cumulative weighted histogram.\"\n    }\n  ]\n}\n",[1025,1030,1031],{"type":1027},"\n{\n  \"@context\": \"https:\u002F\u002Fschema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"How to Sample RUM Data Without Biasing Your p75\",\n  \"description\": \"How to reduce RUM volume with session-level, deterministic sampling that keeps the 75th percentile honest across segments.\",\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\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsampling-rum-data-without-biasing-p75\u002F\"\n  }\n}\n",[1025,1033,1034],{"type":1027},"\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\": \"Core Web Vitals & Measurement\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 3,\n      \"name\": \"RUM Beacons & Field Data Collection\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002F\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 4,\n      \"name\": \"Sampling RUM Data Without Biasing p75\",\n      \"item\": \"https:\u002F\u002Ffrontend-performance.com\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsampling-rum-data-without-biasing-p75\u002F\"\n    }\n  ]\n}\n",[1036,1037,1038],"style",{},"html pre.shiki code .sjfSM, html code.shiki .sjfSM{--shiki-default:#66707B;--shiki-dark:#BDC4CC;--shiki-light:#66707B}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 .sPXB4, html code.shiki .sPXB4{--shiki-default:#023B95;--shiki-dark:#91CBFF;--shiki-light:#023B95}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);}html pre.shiki code .sZ8jY, html code.shiki .sZ8jY{--shiki-default:#032563;--shiki-dark:#ADDCFF;--shiki-light:#032563}",{"title":329,"searchDepth":343,"depth":343,"links":1040},[1041,1042,1043,1049,1050,1051,1052,1053],{"id":153,"depth":343,"text":154},{"id":191,"depth":343,"text":192},{"id":313,"depth":343,"text":314,"children":1044},[1045,1046,1047,1048],{"id":318,"depth":371,"text":319},{"id":571,"depth":371,"text":572},{"id":617,"depth":371,"text":618},{"id":739,"depth":371,"text":740},{"id":916,"depth":343,"text":917},{"id":923,"depth":343,"text":924},{"id":930,"depth":343,"text":931},{"id":960,"depth":343,"text":961},{"id":999,"depth":343,"text":1000},"How to reduce RUM volume with session-level, deterministic sampling that keeps the 75th percentile honest across segments.","md",{"slug":1057,"type":1058,"breadcrumb":1059,"datePublished":1066,"dateModified":1066},"sampling-rum-data-without-biasing-p75","article",[1060,1062,1063,1064],{"name":1061,"url":479},"Home",{"name":27,"url":26},{"name":22,"url":21},{"name":5,"url":1065},"\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsampling-rum-data-without-biasing-p75\u002F","2026-10-06",true,"\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsampling-rum-data-without-biasing-p75",{"title":1070,"description":1071},"Sampling RUM Data Without Biasing the p75","Sampling RUM beacons cuts cost, but sampling the wrong unit or at the wrong moment skews p75 LCP, INP and CLS. Sample sessions deterministically and weight them.","core-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsampling-rum-data-without-biasing-p75\u002Findex","CPQK38rd9_If5xckCpa6mWztwMjJjrhJZrlYOedch9I",[1075,1079],{"title":1076,"path":1077,"stem":1078},"Exposing Backend Timing with Server-Timing Headers","\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fexposing-backend-timing-with-server-timing-headers","core-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fexposing-backend-timing-with-server-timing-headers\u002Findex",{"title":1080,"path":1081,"stem":1082},"Segmenting RUM by Device and Connection","\u002Fcore-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsegmenting-rum-by-device-and-connection","core-web-vitals-measurement\u002Frum-beacons-and-field-data-collection\u002Fsegmenting-rum-by-device-and-connection\u002Findex",1791308076941]