[{"data":1,"prerenderedAt":743},["ShallowReactive",2],{"blog-shop-search-analytics-en":3},{"slug":4,"published":5,"minutes":6,"category":7,"tags":8,"keywords":14,"about":25,"sources":35,"cover":72,"og":73,"expertise":74,"locales":75,"lang":76,"title":79,"description":80,"coverAlt":81,"metaTitle":82,"takeaways":83,"faq":89,"toc":105,"blocks":133,"others":471},"shop-search-analytics","2026-10-06",10,"web",[9,10,11,12,13],"Search analytics","Zero-result search","Position bias","Search logs","GDPR",[15,16,17,18,19,20,21,22,23,24],"shop search analytics","zero result rate","zero result search queries","site search metrics","search click-through rate position bias","query intent classification LLM","search abandonment rate","synonyms from zero-result queries","interleaving vs A\u002FB testing search","search log retention GDPR",[26,29,32],{"name":27,"url":28},"Information retrieval","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FInformation_retrieval",{"name":30,"url":31},"Learning to rank","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FLearning_to_rank",{"name":33,"url":34},"General Data Protection Regulation","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FGeneral_Data_Protection_Regulation",[36,39,42,45,48,51,54,57,60,63,66,69],{"title":37,"url":38},"Algolia: search analytics concepts (metrics and definitions)","https:\u002F\u002Fwww.algolia.com\u002Fdoc\u002Fguides\u002Fsearch-analytics\u002Fconcepts\u002F",{"title":40,"url":41},"Algolia: query aggregation and userToken","https:\u002F\u002Fwww.algolia.com\u002Fdoc\u002Fguides\u002Fsearch-analytics\u002Fconcepts\u002Fquery-aggregation\u002F",{"title":43,"url":44},"User Behavior Insights (UBI) specification 1.3.0","https:\u002F\u002Fgithub.com\u002Fo19s\u002Fubi",{"title":46,"url":47},"Google Research: position bias estimation for unbiased learning to rank in personal search (WSDM 2018)","https:\u002F\u002Fresearch.google\u002Fpubs\u002Fposition-bias-estimation-for-unbiased-learning-to-rank-in-personal-search\u002F",{"title":49,"url":50},"eBay: click propensity estimation for e-commerce search (SPIRE 2019)","https:\u002F\u002Farxiv.org\u002Fabs\u002F1812.09338",{"title":52,"url":53},"Chapelle, Joachims, Radlinski, Yue: interleaved search evaluation (TOIS 2012)","https:\u002F\u002Fwww.cs.cornell.edu\u002Fpeople\u002Ftj\u002Fpublications\u002Fchapelle_etal_12a.pdf",{"title":55,"url":56},"Shopping Queries Dataset (ESCI), KDD Cup 2022","https:\u002F\u002Farxiv.org\u002Fabs\u002F2206.06588",{"title":58,"url":59},"BERTopic: neural topic modeling with class-based TF-IDF","https:\u002F\u002Farxiv.org\u002Fabs\u002F2203.05794",{"title":61,"url":62},"Hello Retail: ecommerce search statistics (24 Feb 2026)","https:\u002F\u002Fhelloretail.com\u002Fen\u002Fblog\u002F2026-02-24-ecommerce-search-statistics\u002F",{"title":64,"url":65},"Algolia: adding synonyms","https:\u002F\u002Fwww.algolia.com\u002Fdoc\u002Fguides\u002Fmanaging-results\u002Foptimize-search-results\u002Fadding-synonyms\u002F",{"title":67,"url":68},"Regulation (EU) 2016\u002F679 (GDPR), EUR-Lex","https:\u002F\u002Feur-lex.europa.eu\u002Feli\u002Freg\u002F2016\u002F679\u002Foj",{"title":70,"url":71},"Arbeitsverfassungsgesetz § 96, RIS (consolidated text)","https:\u002F\u002Fwww.ris.bka.gv.at\u002FNormDokument.wxe?Abfrage=Bundesnormen&Gesetzesnummer=10008329&Paragraf=96","\u002Fimages\u002Fblog\u002Fshop-search-analytics\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fshop-search-analytics\u002Fog.jpg","b2b-ecommerce-developer",[76,77,78],"en","de","hu","Shop search analytics: what to log, and the zero-result fixes to ship first","Instrument on-site search with one event schema, five metrics with targets, position-bias-aware reading, a weekly zero-result review and GDPR limits.","A magnifying glass beside a bar chart with one empty bar.","Shop search analytics: what to log · Balázs Csorba",[84,85,86,87,88],"Log one search event and one follow-up event per interaction, joined by a query_id, before you look at any dashboard.","Start the weekly loop with zero-result queries: they are the cheapest failures to find, and many are vocabulary gaps with a known fix.","Read click-through by position as a description of where clicks land, not as a measure of relevance, and test ranking changes with interleaving or A\u002FB tests.","Sort each failure into a catalogue, vocabulary or intent gap before choosing a fix, so catalogue problems are not patched with synonyms.","Keep session identifiers pseudonymous and retention windows short; search logs are personal data, and logs that can reach named employees fall under § 96 ArbVG in Austria.",[90,93,96,99,102],{"q":91,"a":92},"What is a good zero-result rate for a shop?","The only public calibration point in this article is vendor guidance from Hello Retail, published in February 2026: an average of 10–15% of searches return nothing, with a target below 5%. Treat that as a rough line. Set your own baseline from your logs and judge changes against it.",{"q":94,"a":95},"Which search events should you log first?","Log the search event with the query text, filters, page and result count, and the click event with the query_id, object identifier and position. Without a shared query_id you cannot connect a click to the search that produced it.",{"q":97,"a":98},"Why is click-through rate not enough on its own?","A click shows interest, not success, and clicks concentrate on higher positions regardless of relevance. Read CTR by position with that bias in mind, and judge ranking changes with a method that does not depend on the position curve.",{"q":100,"a":101},"Is interleaving better than A\u002FB testing for search?","For ranking changes, interleaving reaches a decision with far fewer queries. Chapelle et al. reported more than an order of magnitude fewer queries than click-based signals. A\u002FB testing is still the right tool for large changes and for business metrics such as conversion and revenue.",{"q":103,"a":104},"Are search logs personal data under the GDPR?","They can be. A query linked to an account, a session or an IP address can identify a person, so the GDPR applies. Minimise the fields you collect, pseudonymise identifiers and set retention windows that match the purpose.",[106,109,112,115,118,121,124,127,130],{"id":107,"title":108},"what-to-fix-first","What should you fix first?",{"id":110,"title":111},"where-search-analytics-usually-fails","When does search analytics mislead?",{"id":113,"title":114},"search-log-schema","What should one search event contain?",{"id":116,"title":117},"core-metrics-and-targets","Which five metrics should you track?",{"id":119,"title":120},"position-bias-and-why-raw-ctr-misleads","Why does raw CTR by position mislead?",{"id":122,"title":123},"classifying-zero-result-queries","How do you group zero-result queries?",{"id":125,"title":126},"weekly-review-loop","What does the weekly review look like?",{"id":128,"title":129},"privacy-and-retention","How long should search logs be kept?",{"id":131,"title":132},"sources","Sources",[134,138,147,150,153,156,157,160,190,191,199,202,205,211,212,215,304,307,308,315,322,329,330,336,342,345,346,349,352,382,385,389,397,398,404,410,417,424,432,433],{"type":135,"content":136},"paragraph",[137],"Most shops log that a search happened. Far fewer log whether it worked. The measurement that does is a loop: every search writes one event with the query, its filters, the result count and a join key; every click writes a follow-up event that points back to that key; and once a week someone reads the queries that returned nothing or got no click and turns them into a fix. This article describes that loop: the event schema, five metrics with their definitions and first actions, a correction for position bias, a way to group failures, and the limits on what you should collect.",{"type":135,"content":139},[140,141,146],"The loop does not replace retrieval work. Matching, query rewriting and a clean catalogue decide what a search can find, and ",{"tag":142,"to":143,"children":144},"link","\u002Fblog\u002Fsemantic-product-search-b2b",[145],"semantic product search for B2B"," covers that side. Analytics shows which of those problems shoppers actually hit. The metric definitions below follow how Algolia documents its analytics product, and the event shape follows the open User Behavior Insights (UBI) specification, so the design does not depend on one vendor.",{"type":148,"level":149,"id":107,"text":108},"heading",2,{"type":135,"content":151},[152],"Fix the logging gaps first, then the zero-result queries, then the searches without clicks, and only then the ranking. Every other number is only as good as the events behind it, so logging comes first. Zero-result queries come next because they are the cheapest failures to find, and many are vocabulary gaps with a known fix. In the first two weeks of a retro-fit the goal is not a dashboard. It is one complete week of events that you can export, read and act on.",{"type":135,"content":154},[155],"A workable order for a shop without search analytics runs as follows. Add a search event and a click event that share a query_id. Export one week of zero-result queries and read them by hand. Ship three to five synonym or redirect fixes. Add the no-click view. Start an experiment only after the baseline has been stable for a few weeks. Each step is useful on its own, so the full instrumentation does not have to exist before you learn something.",{"type":148,"level":149,"id":110,"text":111},{"type":135,"content":158},[159],"Search analytics misleads when traffic is too thin to show a difference, when a single rate is read as a verdict, when seasonality is ignored, and when a few repeat trade buyers are averaged in with everyone else. Each of these is common in B2B shops, where a small group of customers often runs most searches, using part numbers and saved carts.",{"type":161,"ordered":162,"items":163},"list",false,[164,170,175,180,185],[165,169],{"tag":166,"children":167},"strong",[168],"Too little traffic."," A change that moves a rate by a few points needs enough searches per variant before the result means anything. For a category with a few hundred searches a week, count weeks rather than days, and accept that some questions will stay open.",[171,174],{"tag":166,"children":172},[173],"CTR as a verdict."," A click shows interest, not success. A shopper who clicks the first result, sees the wrong part and leaves has produced a click and a failed search.",[176,179],{"tag":166,"children":177},[178],"Seasonality."," Zero-result rates for seasonal goods or spare parts move with the calendar, so compare the same weeks year on year, or like with like, rather than the last week against a quiet one.",[181,184],{"tag":166,"children":182},[183],"B2B traffic skew."," Repeat buyers who search by part number can dominate the averages. Where your data allows it, segment by account type before reading a rate as a shop-wide result.",[186,189],{"tag":166,"children":187},[188],"Logs you should not keep."," Some fields do not help the loop and add legal risk. The privacy section explains which ones to leave out.",{"type":148,"level":149,"id":113,"text":114},{"type":135,"content":192},[193,194,198],"One search event records the query and the context it ran in. Separate events record what the shopper did next, and the two are joined by a query_id that the search service returns with each response. The UBI specification names the fields that make a search log joinable: query_id, the query text, filters, page, a client_id that stays stable when a visitor moves from anonymous to logged in, the position on click events, and the object identifier, such as a SKU. ",{"tag":195,"href":44,"children":196},"a",[197],"The UBI specification"," uses an item click on a SKU as its example. A sketch of the two events for a shop looks like this:",{"type":200,"code":201},"code","\u002F\u002F search event\n{\n  \"query_id\": \"3f9c0b7e-6d2a-4c1e-9a55-2b8f1d7e4a10\",\n  \"client_id\": \"c-7b1e44\",\n  \"user_query\": { \"query\": \"m8x25 hex bolt a2\" },\n  \"filter\": [\"in_stock:true\"],\n  \"page\": 1,\n  \"result_count\": 0\n}\n\n\u002F\u002F click event, same query_id\n{\n  \"query_id\": \"3f9c0b7e-6d2a-4c1e-9a55-2b8f1d7e4a10\",\n  \"client_id\": \"c-7b1e44\",\n  \"event_attributes\": { \"position\": 3 },\n  \"object\": { \"object_id\": \"SKU-100234\", \"object_id_field\": \"sku\" }\n}",{"type":135,"content":203},[204],"The query_id and client_id are load-bearing. Without them you cannot connect a click to the search that produced it, or see whether a shopper refined the same question. The filter and page fields show whether a zero-result search was over-filtered, which is often the real problem. Position is what makes click data usable for the bias correction later in this article. Store the two event types in separate tables and keep raw query text in its own column, so that it can be deleted on a schedule without losing the aggregates.",{"type":206,"src":207,"alt":208,"wide":209,"caption":210},"image","\u002Fimages\u002Fblog\u002Fshop-search-analytics\u002Fdiagram-12.webp","Instrumented search path Four steps from left to right: a search request writes a search event with the query and filters; the shopper clicks a result and the click writes a click event with the same query_id and the position; the weekly export groups the searches that returned nothing or got no click.",true,"Each search and each click writes an event; the weekly export groups the failures from the same query_id join.",{"type":148,"level":149,"id":116,"text":117},{"type":135,"content":213},[214],"Five metrics cover most of the loop. The definitions follow the vendor wording, so your numbers can be compared with documentation, and each row names the event field behind it, so that a moving number can be traced to its events. Algolia’s analytics concepts list the same family of views, including searches without results and searches without clicks, which is where the weekly review starts.",{"type":216,"head":217,"rows":228},"table",[218,220,222,224,226],[219],"Metric",[221],"Definition (vendor wording)",[223],"Source field",[225],"Benchmark or target",[227],"First action when it moves the wrong way",[229,247,261,273,290],[230,232,234,239,245],[231],"Zero-result rate",[233],"Share of searches that return no results (Algolia calls it the no-results rate)",[235,238],{"tag":200,"children":236},[237],"result_count"," on the search event",[240,241,244],"10–15% average, under 5% target (",{"tag":195,"href":62,"children":242},[243],"Hello Retail",")",[246],"Triage the week’s largest zero-result clusters",[248,250,252,257,259],[249],"Click-through rate",[251],"Share of tracked searches with at least one click; several clicks in one search count once",[253,256],{"tag":200,"children":254},[255],"query_id"," joined to click events",[258],"No public average; set your own baseline",[260],"Check click position before blaming relevance",[262,264,266,270,271],[263],"No-click rate",[265],"Unique searches with no click, divided by unique searches; it does not add up with CTR to 100%",[267,269],{"tag":200,"children":268},[255]," with no matching click",[258],[272],"Review the no-click queries with the largest volume",[274,276,278,286,288],[275],"Refinement rate",[277],"Share of searches followed by another query from the same client in the same session (working definition used in this article)",[279,282,283],{"tag":200,"children":280},[281],"client_id"," and ",{"tag":200,"children":284},[285],"user_query",[287],"Set your own baseline",[289],"Check synonyms and default filters on the refined queries",[291,293,295,300,302],[292],"Click position",[294],"Average position of the clicked results; raw, not corrected for bias (clicks at 1, 1, 3 and 10 average 3.75)",[296,299],{"tag":200,"children":297},[298],"event_attributes.position"," on the click event",[301],"No public average",[303],"Read by position only after the bias check in this article",{"type":135,"content":305},[306],"The targets are where public evidence is thin. The one calibration point here is vendor guidance from Hello Retail, published in February 2026, which puts the average zero-result rate at 10–15% of searches and a target below 5%. It is a vendor blog post, not a study, so use it as a line to test against rather than a goal. For click-through and no-click rates there is no reliable public average. Set your own baseline from four to six weeks of logs, and change it only when a change has been tested.",{"type":148,"level":149,"id":119,"text":120},{"type":135,"content":309},[310,311,314],"Raw click position mostly describes where results were, not how good they were. Shoppers click the top result more often because it sits on top. Google’s WSDM 2018 paper on position bias says that estimating those propensities by randomising results is “not desired because result randomization can negatively impact users’ search experience”, and proposes estimating them from regular click data instead (",{"tag":195,"href":47,"children":312},[313],"Google Research",").",{"type":135,"content":316},[317,318,321],"eBay’s SPIRE 2019 work goes further and estimates click propensities directly from e-commerce query–document pairs that appear at different ranks, with no live intervention and no relevance model, up to rank 500 (",{"tag":195,"href":50,"children":319},[320],"arXiv","). Most shops will not build that. The practical rule is simpler: do not read a CTR-by-position chart as a relevance chart. Use it to see where clicks concentrate, and judge ranking changes with a method that does not depend on the position curve.",{"type":135,"content":323},[324,325,328],"Interleaving is that method. It mixes the results of two rankers into one list and credits each click to the ranker that supplied the clicked result. Chapelle, Joachims, Radlinski and Yue reported that interleaving reduced the number of queries needed by over an order of magnitude compared with click-based signals, and that one judged query–document pair gave about as much sensitivity as one or two queries with clicks (",{"tag":195,"href":53,"children":326},[327],"Chapelle et al., TOIS 2012","). Plain A\u002FB testing still answers business questions such as conversion and revenue, and it is the right tool for large changes. For ranking changes, interleaving reaches an answer with far less traffic.",{"type":148,"level":149,"id":122,"text":123},{"type":135,"content":331},[332,333,335],"Group them in stages, cheapest first. Rules catch the obvious cases, such as a misspelled brand name or a SKU fragment. Normalisation handles case, separators, unit notation and plural forms. The queries that remain go through an embedding model and a clustering step. BERTopic describes the standard recipe: embed the documents with a pretrained transformer, cluster the embeddings, and label the topics with class-based TF-IDF (",{"tag":195,"href":59,"children":334},[320],"). A language model then names each cluster and assigns it a label.",{"type":135,"content":337},[338,339,341],"The label vocabulary matters more than the tooling. Amazon’s Shopping Queries Dataset judges query–product pairs as Exact, Substitute, Complement or Irrelevant. It covers about 130,000 unique queries and 2.6 million manual judgements in English, Japanese and Spanish, and it was released for KDD Cup 2022 (",{"tag":195,"href":56,"children":340},[320],"). You do not need the data to borrow the vocabulary. For triage, a zero-result cluster usually reads as one of three gaps: a catalogue gap, where the product is not in the shop; a vocabulary gap, where the product exists under other words; or an intent gap, where the shopper asks for something the shop does not frame as a product, such as a compatibility question.",{"type":135,"content":343},[344],"The labelling step is cheap by design. It sees cluster names and a few example queries rather than every search, so its cost follows the size of the cluster summary, not the shop’s traffic. When the weekly export has only a few dozen distinct zero-result queries, read them by hand. Clustering pays off when the list is long.",{"type":148,"level":149,"id":125,"text":126},{"type":135,"content":347},[348],"The loop runs once a week and ends in one change. Export the week’s zero-result and no-click queries. Cluster and label them. Decide which gap each cluster is. Ship one fix, record it in a change log, and measure the following week, or test the fix if it is risky. Closing the loop with one change at a time keeps the attribution clean.",{"type":135,"content":350},[351],"The fixes fall into four groups, and the gap decides which one to use.",{"type":161,"ordered":162,"items":353},[354,362,367,372],[355,358,359,314],{"tag":166,"children":356},[357],"Synonym"," for a vocabulary gap. Algolia’s documented workflow starts from search analytics and adds synonyms of several kinds: regular, one-way, alternative corrections and placeholders. Synonyms do not cascade, and the documentation warns against overusing them (",{"tag":195,"href":65,"children":360},[361],"Algolia",[363,366],{"tag":166,"children":364},[365],"Redirect"," for a query with one clear destination, such as a category page or a campaign landing page.",[368,371],{"tag":166,"children":369},[370],"Boost or pin"," for a product that already matches the query but ranks below weaker results.",[373,376,377,381],{"tag":166,"children":374},[375],"Data fix"," for a catalogue gap. If the product exists but its name or attributes do not carry the word the customer used, the fix belongs to the catalogue owner. ",{"tag":142,"to":378,"children":379},"\u002Fblog\u002Frag-product-catalog-pim-data",[380],"Catalogue data quality"," covers how to route that work.",{"type":135,"content":383},[384],"Clusters that are really navigation problems, such as a missing category link, are not search problems. Route them out of the loop and record them as rejected, so the same cluster does not come back every week.",{"type":206,"src":386,"alt":387,"wide":209,"caption":388},"\u002Fimages\u002Fblog\u002Fshop-search-analytics\u002Fdiagram-30.webp","Weekly search review as a closed loop Six boxes. Across the top, from left to right: export, cluster and label, ship one fix, experiment. The experiment feeds a dashboard at the bottom right, and an arrow from the dashboard returns to the export box, which closes the loop. A dashed branch from the cluster box leads to a rejected box for clusters that are navigation or catalogue issues rather than search problems.","The weekly loop as a closed circuit: one fix per week, measured against a dated baseline, with an exit for problems that are not search problems.",{"type":135,"content":390},[391,392,396],"The experiment step closes the circuit. Ship one change at a time, log its date and the cluster it targeted, and read the next week’s numbers against that date. Use an A\u002FB test for a large change with enough traffic. Use interleaving for ranking changes where you need an answer sooner. The rewriting mechanics behind many of these fixes are in ",{"tag":142,"to":393,"children":394},"\u002Fblog\u002Fconversational-search-query-rewriting",[395],"conversational search query rewriting","; the weekly review is how you find which rewrites are worth making.",{"type":148,"level":149,"id":128,"text":129},{"type":135,"content":399},[400,401,314],"Keep only the fields the loop uses, and only for as long as the loop needs them. Under the GDPR, data minimisation (Article 5(1)(c)) and storage limitation (Article 5(1)(e)) apply to search logs as they do to any personal data, and Article 32 lists pseudonymisation and encryption among the security measures (",{"tag":195,"href":68,"children":402},[403],"EUR-Lex",{"type":135,"content":405},[406,407,409],"In practice that means pseudonymous session identifiers instead of account numbers, raw query text in its own table with its own retention window, and no IP addresses after ingestion. The default matters here. Algolia uses IP addresses to tell users apart unless you pass a userToken, and it warns that backend searches otherwise group every user under the server’s IP (",{"tag":195,"href":41,"children":408},[361],"). An IP address is personal data you would rather replace with a pseudonymous identifier before it reaches the log.",{"type":411,"variant":412,"title":413,"body":414},"callout","warn","Keep raw query text out of the aggregates",[415],[416],"Zero-result rates and CTR by position do not need raw query text once the weekly review is done. Delete or hash the raw text on the retention schedule and keep the counts.",{"type":135,"content":418},[419,420,423],"If logs can reach named employees, the question changes. In Austria, § 96 Abs. 1 Z 3 of the Arbeitsverfassungsgesetz makes the introduction of control measures and technical systems for monitoring employees subject to works-council consent where human dignity is affected (",{"tag":195,"href":71,"children":421},[422],"RIS","). An internal search log that can be traced to a named employee is the case to check first, and the safer design keeps the join key pseudonymous and the reporting aggregated.",{"type":135,"content":425},[426,427,431],"Retention periods are a policy decision for your business, not a vendor default. Write the window into the schema documentation and enforce it with a scheduled delete, so the weekly export keeps working without the raw history growing forever. If you build this for a B2B shop, my ",{"tag":142,"to":428,"children":429},"\u002Fexpertise\u002Fb2b-ecommerce-developer",[430],"B2B e-commerce work"," covers the catalogue side as well as the search side.",{"type":148,"level":149,"id":131,"text":132},{"type":161,"ordered":209,"items":434},[435,438,441,444,447,450,453,456,459,462,465,468],[436],{"tag":195,"href":38,"children":437},[37],[439],{"tag":195,"href":41,"children":440},[40],[442],{"tag":195,"href":44,"children":443},[43],[445],{"tag":195,"href":47,"children":446},[46],[448],{"tag":195,"href":50,"children":449},[49],[451],{"tag":195,"href":53,"children":452},[52],[454],{"tag":195,"href":56,"children":455},[55],[457],{"tag":195,"href":59,"children":458},[58],[460],{"tag":195,"href":62,"children":461},[61],[463],{"tag":195,"href":65,"children":464},[64],[466],{"tag":195,"href":68,"children":467},[67],[469],{"tag":195,"href":71,"children":470},[70],[472,545,601,675],{"slug":473,"published":474,"minutes":6,"category":7,"tags":475,"keywords":481,"about":493,"sources":502,"cover":539,"og":540,"expertise":74,"locales":541,"lang":76,"title":542,"description":543,"coverAlt":544},"schema-org-structured-data-b2b-shop","2026-10-17",[476,477,478,479,480],"Schema.org","Structured data","B2B e-commerce","Technical SEO","Nuxt",[482,483,484,485,486,487,488,489,490,491,492],"schema.org b2b shop","product structured data b2b","merchant listing structured data","product snippet vs merchant listing","unitpricespecification referencequantity","productgroup variants structured data","organization schema vatid","b2b prices behind login seo","json-ld nuxt schema org","merchant return policy structured data","mpn gtin structured data",[494,496,499],{"name":476,"url":495},"https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FSchema.org",{"name":497,"url":498},"JSON-LD","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FJSON-LD",{"name":500,"url":501},"Business-to-business","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FBusiness-to-business",[503,506,509,512,515,518,521,524,527,530,533,536],{"title":504,"url":505},"Google Search Central: Introduction to Product structured data","https:\u002F\u002Fdevelopers.google.com\u002Fsearch\u002Fdocs\u002Fappearance\u002Fstructured-data\u002Fproduct",{"title":507,"url":508},"Google Search Central: Merchant listing (Product, Offer) structured data","https:\u002F\u002Fdevelopers.google.com\u002Fsearch\u002Fdocs\u002Fappearance\u002Fstructured-data\u002Fmerchant-listing",{"title":510,"url":511},"Google Search Central: Product snippet structured data","https:\u002F\u002Fdevelopers.google.com\u002Fsearch\u002Fdocs\u002Fappearance\u002Fstructured-data\u002Fproduct-snippet",{"title":513,"url":514},"Google Search Central: Product variant structured data","https:\u002F\u002Fdevelopers.google.com\u002Fsearch\u002Fdocs\u002Fappearance\u002Fstructured-data\u002Fproduct-variants",{"title":516,"url":517},"Google Search Central: Organization structured data","https:\u002F\u002Fdevelopers.google.com\u002Fsearch\u002Fdocs\u002Fappearance\u002Fstructured-data\u002Forganization",{"title":519,"url":520},"Google Search Central: Merchant return policy structured data","https:\u002F\u002Fdevelopers.google.com\u002Fsearch\u002Fdocs\u002Fappearance\u002Fstructured-data\u002Freturn-policy",{"title":522,"url":523},"Google Search Central: General structured data guidelines","https:\u002F\u002Fdevelopers.google.com\u002Fsearch\u002Fdocs\u002Fappearance\u002Fstructured-data\u002Fsd-policies",{"title":525,"url":526},"Google Search Central: Generate structured data with JavaScript","https:\u002F\u002Fdevelopers.google.com\u002Fsearch\u002Fdocs\u002Fappearance\u002Fstructured-data\u002Fgenerate-structured-data-with-javascript",{"title":528,"url":529},"Schema.org: Offer","https:\u002F\u002Fschema.org\u002FOffer",{"title":531,"url":532},"Schema.org: UnitPriceSpecification","https:\u002F\u002Fschema.org\u002FUnitPriceSpecification",{"title":534,"url":535},"Unhead: Product schema (defineProduct)","https:\u002F\u002Funhead.unjs.io\u002Fdocs\u002Fschema-org\u002Fapi\u002Fschema\u002Fproduct",{"title":537,"url":538},"Nuxt SEO: Schema.org identity setup","https:\u002F\u002Fnuxtseo.com\u002Fdocs\u002Fschema-org\u002Fguides\u002Fsetup-identity","\u002Fimages\u002Fblog\u002Fschema-org-structured-data-b2b-shop\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fschema-org-structured-data-b2b-shop\u002Fog.jpg",[76,77,78],"Schema.org structured data for B2B shops: prices behind logins, units and variants","Product markup for B2B shops: snippet or merchant listing, which price to publish, part numbers, unit pricing, variants, Organization and SSR in Nuxt.","A product rectangle with a framed outline and a small price slot hidden behind a low wall.",{"slug":546,"published":474,"minutes":547,"category":7,"tags":548,"keywords":553,"about":565,"sources":573,"cover":595,"og":596,"expertise":74,"locales":597,"lang":76,"title":598,"description":599,"coverAlt":600},"ai-assistant-b2b-shop-customer-support",9,[478,549,550,551,552],"AI assistant","Customer support","LLM agents","EU AI Act",[554,555,556,557,558,559,560,561,562,563,564],"ai assistant b2b shop","ai customer support b2b ecommerce","llm chatbot order status","ai agent customer service tools","chatbot liability air canada","klarna ai assistant results","human handoff chatbot design","eu ai act chatbot disclosure","owasp excessive agency","ai support resolution rate","b2b customer portal chatbot",[566,569,572],{"name":567,"url":568},"Customer service","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FCustomer_service",{"name":570,"url":571},"Chatbot","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FChatbot",{"name":500,"url":501},[574,577,580,583,586,589,592],{"title":575,"url":576},"Klarna: AI assistant handles two-thirds of customer service chats in its first month (press release, 2024)","https:\u002F\u002Fwww.klarna.com\u002Finternational\u002Fpress\u002Fklarna-ai-assistant-handles-two-thirds-of-customer-service-chats-in-its-first-month\u002F",{"title":578,"url":579},"Entrepreneur: Klarna is hiring customer service agents again, according to its CEO (May 2025)","https:\u002F\u002Fwww.entrepreneur.com\u002Fbusiness-news\u002Fklarna-ceo-reverses-course-by-hiring-more-humans-not-ai\u002F491396",{"title":581,"url":582},"ABA Business Law Today: BC tribunal confirms companies remain liable for information provided by AI chatbot","https:\u002F\u002Fwww.americanbar.org\u002Fgroups\u002Fbusiness_law\u002Fresources\u002Fbusiness-law-today\u002F2024-february\u002Fbc-tribunal-confirms-companies-remain-liable-information-provided-ai-chatbot\u002F",{"title":584,"url":585},"OWASP GenAI Security Project: LLM06:2025 Excessive Agency","https:\u002F\u002Fgenai.owasp.org\u002Fllmrisk\u002Fllm062025-excessive-agency\u002F",{"title":587,"url":588},"OWASP GenAI Security Project: LLM05:2025 Improper Output Handling","https:\u002F\u002Fgenai.owasp.org\u002Fllmrisk\u002Fllm052025-improper-output-handling\u002F",{"title":590,"url":591},"EU AI Act, Article 50: Transparency obligations","https:\u002F\u002Fartificialintelligenceact.eu\u002Farticle\u002F50\u002F",{"title":593,"url":594},"Intercom: Fin pricing and billable outcomes","https:\u002F\u002Ffin.ai\u002Fpricing","\u002Fimages\u002Fblog\u002Fai-assistant-b2b-shop-customer-support\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fai-assistant-b2b-shop-customer-support\u002Fog.jpg",[76,77,78],"An AI assistant for B2B shop support: tools, permissions and the human handoff","How to build an AI support assistant for a B2B shop: which requests to automate, tools that run in the customer context, handoff, AI Act and metrics.","A tall wall with one narrow gap; an arrow passes through it into a boxed enclosure of three squares, and another leads down to a tray.",{"slug":602,"published":474,"minutes":603,"category":7,"tags":604,"keywords":609,"about":621,"sources":631,"cover":668,"og":669,"expertise":670,"locales":671,"lang":76,"title":672,"description":673,"coverAlt":674},"vue-ai-chat-ui-streaming-accessibility",11,[605,480,606,607,608],"Vue","Accessibility","Streaming","AI chat",[610,611,612,613,614,615,616,617,618,619,620],"vue ai chat ui","nuxt llm streaming","sse vs fetch streaming","aria-live streaming text","accessible chat interface","abort fetch stream vue","dompurify markdown llm","role log chat","reduced motion chat ui","wcag 2.2 chat","screen reader streaming",[622,625,628],{"name":623,"url":624},"Web accessibility","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FWeb_accessibility",{"name":626,"url":627},"Server-sent events","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FServer-sent_events",{"name":629,"url":630},"Vue.js","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FVue.js",[632,635,638,641,644,647,650,653,656,659,662,665],{"title":633,"url":634},"MDN: Using server-sent events","https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FServer-sent_events\u002FUsing_server-sent_events",{"title":636,"url":637},"MDN: AbortController","https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FAbortController",{"title":639,"url":640},"MDN: ReadableStream","https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FReadableStream",{"title":642,"url":643},"MDN: TextDecoderStream","https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAPI\u002FTextDecoderStream",{"title":645,"url":646},"MDN: ARIA log role","https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FAccessibility\u002FARIA\u002FReference\u002FRoles\u002Flog_role",{"title":648,"url":649},"W3C: Understanding SC 4.1.3 Status Messages","https:\u002F\u002Fwww.w3.org\u002FWAI\u002FWCAG22\u002FUnderstanding\u002Fstatus-messages.html",{"title":651,"url":652},"W3C WAI: What's new in WCAG 2.2","https:\u002F\u002Fwww.w3.org\u002FWAI\u002Fstandards-guidelines\u002Fwcag\u002Fnew-in-22\u002F",{"title":654,"url":655},"MDN: prefers-reduced-motion","https:\u002F\u002Fdeveloper.mozilla.org\u002Fen-US\u002Fdocs\u002FWeb\u002FCSS\u002F@media\u002Fprefers-reduced-motion",{"title":657,"url":658},"DOMPurify README","https:\u002F\u002Fgithub.com\u002Fcure53\u002FDOMPurify",{"title":660,"url":661},"markdown-it README","https:\u002F\u002Fgithub.com\u002Fmarkdown-it\u002Fmarkdown-it",{"title":663,"url":664},"AI SDK docs: useChat","https:\u002F\u002Fai-sdk.dev\u002Fdocs\u002Fai-sdk-ui\u002Fchatbot",{"title":666,"url":667},"Vue docs: nextTick","https:\u002F\u002Fvuejs.org\u002Fapi\u002Fgeneral.html#nexttick","\u002Fimages\u002Fblog\u002Fvue-ai-chat-ui-streaming-accessibility\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fvue-ai-chat-ui-streaming-accessibility\u002Fog.jpg","vue-nuxt-developer",[76,77,78],"Streaming AI chat in Vue and Nuxt: accessible by design","How to build a Vue or Nuxt AI chat UI: fetch streams, abort and retry, safe markdown rendering, aria-live announcements, keyboard support and reduced motion.","A message card with a careful caret, a dotted line opening into ripples and a check.",{"slug":676,"published":474,"minutes":547,"category":7,"tags":677,"keywords":682,"about":694,"sources":704,"cover":737,"og":738,"expertise":670,"locales":739,"lang":76,"title":740,"description":741,"coverAlt":742},"llm-translation-pipeline-i18n",[678,679,680,605,681],"Translation","i18n","LLM","Localization",[683,684,685,686,687,688,689,690,691,692,693],"llm translation pipeline","icu messageformat placeholders","vue i18n llm translation","translation memory llm","glossary enforcement translation","german informal sie du","hungarian translation quality llm","structured output json translation","machine translation post-editing","locale file validation","cldr plural categories",[695,698,701],{"name":696,"url":697},"Internationalization and localization","https:\u002F\u002Fen.wikipedia.org\u002Fwiki\u002FInternationalization_and_localization",{"name":699,"url":700},"ICU MessageFormat","https:\u002F\u002Funicode-org.github.io\u002Ficu\u002Fuserguide\u002Fformat_parse\u002Fmessages\u002F",{"name":702,"url":703},"Vue I18n","https:\u002F\u002Fvue-i18n.intlify.dev\u002F",[705,707,710,713,716,719,722,725,728,731,734],{"title":706,"url":700},"Unicode ICU User Guide: Formatting Messages",{"title":708,"url":709},"Vue I18n: Message Format Syntax","https:\u002F\u002Fvue-i18n.intlify.dev\u002Fguide\u002Fessentials\u002Fsyntax",{"title":711,"url":712},"Nuxt i18n: Getting started","https:\u002F\u002Fi18n.nuxtjs.org\u002Fdocs\u002Fgetting-started",{"title":714,"url":715},"Unicode CLDR: Plural rules","https:\u002F\u002Fcldr.unicode.org\u002Findex\u002Fcldr-spec\u002Fplural-rules",{"title":717,"url":718},"OpenAI: Structured outputs","https:\u002F\u002Fplatform.openai.com\u002Fdocs\u002Fguides\u002Fstructured-outputs",{"title":720,"url":721},"DeepL API: Glossaries","https:\u002F\u002Fdevelopers.deepl.com\u002Fdocs\u002Fapi-reference\u002Fglossaries",{"title":723,"url":724},"W3C: Localization vs. internationalization","https:\u002F\u002Fwww.w3.org\u002FInternational\u002Fquestions\u002Fqa-i18n",{"title":726,"url":727},"GNU gettext manual","https:\u002F\u002Fwww.gnu.org\u002Fsoftware\u002Fgettext\u002Fmanual\u002Fgettext.html",{"title":729,"url":730},"RFC 5646: Tags for Identifying Languages","https:\u002F\u002Fwww.rfc-editor.org\u002Frfc\u002Frfc5646",{"title":732,"url":733},"Rat für deutsche Rechtschreibung","https:\u002F\u002Fwww.rechtschreibrat.com\u002F",{"title":735,"url":736},"Microsoft Writing Style Guide","https:\u002F\u002Flearn.microsoft.com\u002Fen-us\u002Fstyle-guide\u002Fwelcome\u002F","\u002Fimages\u002Fblog\u002Fllm-translation-pipeline-i18n\u002Fcover.webp","\u002Fimages\u002Fblog\u002Fllm-translation-pipeline-i18n\u002Fog.jpg",[76,77,78],"An LLM translation pipeline for i18n: glossary, placeholders and review","How to translate product and website strings with LLMs without breaking placeholders, plurals or tone: glossary, ICU messages, QA checks and review gates.","Three source cards, one translated card with a glossary ribbon, then a checked clipboard.",1792337027627]