···301301- `!warn` and `!hide` always apply their effects
302302303303Attempting to set a preference for a system label returns an error.
304304+305305+### Client-Side Filtering
306306+307307+The server filters takedown labels automatically, but clients must apply user preferences for other labels. Here's the pattern:
308308+309309+```typescript
310310+// 1. Fetch preferences once and cache
311311+const prefs = await client.query(`{
312312+ viewerLabelPreferences { val visibility }
313313+}`)
314314+const prefMap = new Map(prefs.map(p => [p.val, p.visibility]))
315315+316316+// 2. Check visibility for each record
317317+function getVisibility(record) {
318318+ for (const label of record.labels ?? []) {
319319+ const vis = prefMap.get(label.val) ?? 'WARN'
320320+ if (vis === 'HIDE') return { show: false }
321321+ if (vis === 'WARN') return { show: true, blur: true }
322322+ }
323323+ return { show: true, blur: false }
324324+}
325325+326326+// 3. Apply in your UI
327327+function RecordCard({ record }) {
328328+ const { show, blur } = getVisibility(record)
329329+330330+ if (!show) return null
331331+332332+ if (blur) {
333333+ return (
334334+ <BlurOverlay onReveal={() => setRevealed(true)}>
335335+ <Content record={record} />
336336+ </BlurOverlay>
337337+ )
338338+ }
339339+340340+ return <Content record={record} />
341341+}
342342+```
343343+344344+Key points:
345345+346346+- Cache preferences at session start or when user updates them
347347+- Default unknown labels to `WARN` for safety
348348+- Multiple labels on one record: apply the most restrictive
349349+- `IGNORE` and `SHOW` both display normally; `SHOW` is for explicit opt-in to adult content