Download index.html from getreadystack/iot-data-notice-lint: direct link, hf CLI and curl.
- Browser
- Download file 45.2 kB
-
https://huggingface.co/spaces/getreadystack/iot-data-notice-lint/resolve/main/index.html
- Command line
-
hf download hf://spaces/getreadystack/iot-data-notice-lint/index.html
-
curl -L -o index.html https://huggingface.co/spaces/getreadystack/iot-data-notice-lint/resolve/main/index.html
45.2 kB
| <html lang="en"> | |
| <head> | |
| <meta charset="utf-8"> | |
| <meta name="viewport" content="width=device-width,initial-scale=1"> | |
| <title>EU Data Act Article 3 Notice — check your device data notice free</title> | |
| <meta name="description" content="Check a smart or connected device's pre-contract data notice for the described buyer information, data-access fees, and retention details under EU Data Act Article 3."> | |
| <style> | |
| :root{color-scheme:light}body{margin:0;font:15px/1.55 system-ui,-apple-system,"Segoe UI",sans-serif;background:#faf9f5;color:#1a1512} | |
| .wrap{max-width:960px;margin:0 auto;padding:28px 18px 60px}h1{font-size:26px;margin:0 0 6px}.lede{color:#4a403a;margin:0 0 16px} | |
| textarea{width:100%;min-height:260px;font:13px/1.45 ui-monospace,Menlo,Consolas,monospace;padding:12px;border:1px solid #d9d0c4;border-radius:8px;box-sizing:border-box} | |
| .bar{display:flex;gap:10px;align-items:center;margin:12px 0}button{font:600 15px system-ui;padding:10px 18px;border:0;border-radius:8px;background:#1a1512;color:#fff;cursor:pointer} | |
| input[type=date]{font:14px system-ui;padding:8px;border:1px solid #d9d0c4;border-radius:6px} | |
| table{border-collapse:collapse;width:100%;font-size:14px;margin-top:10px}th,td{text-align:left;padding:8px 10px;border-bottom:1px solid #eee;vertical-align:top}th{font-size:12px;letter-spacing:.06em;text-transform:uppercase;color:#7a6e65} | |
| .sev.error{color:#a8551f;font-weight:700}.sev.warn,.sev.warning{color:#96691f}.ok{color:#2a6446;font-weight:600}.sum{font-weight:600} | |
| .note{font-size:13px;color:#7a6e65;margin-top:18px}#paid{margin-top:22px;padding:14px 16px;border:1px solid #e2d8cb;border-radius:10px;background:#fffdfa} | |
| </style> | |
| <script data-grow-initializer="">!(function(){window.growMe||((window.growMe=function(e){window.growMe._.push(e);}),(window.growMe._=[]));var e=document.createElement("script");(e.type="text/javascript"),(e.src="https://faves.grow.me/main.js"),(e.defer=!0),e.setAttribute("data-grow-faves-site-id","U2l0ZTphZjljMzgyMC0yMmU5LTRhYjgtYTIxNS03OTRhMGY1N2ExYzM=");var t=document.getElementsByTagName("script")[0];t.parentNode.insertBefore(e,t);})();</script> | |
| <!--yj-canon-s101--><link rel="canonical" href="https://getreadystack.com/tools/iot-data-notice-lint"></head> | |
| <body> | |
| <div class="wrap"> | |
| <h1>EU Data Act Article 3 Notice — check your device data notice free</h1> | |
| <p class="lede">Checks the pre-contract data notice of a smart or connected device sold in the EU against Data Act Article 3(2)-(3): every item the buyer must be told, plus data-access fees and vague retention. Runs entirely in your browser — nothing is uploaded.</p> | |
| <textarea id="src" spellcheck="false">--- | |
| product: Nordlicht T3 smart thermostat | |
| placed_on_market: 2026-10-01 | |
| --- | |
| # Nordlicht T3: product data notice | |
| Before you buy the connected product, here is what happens to your product data. | |
| ## Product data the thermostat generates | |
| - Data types: room temperature, humidity, setpoint, valve position, error codes. | |
| - Format: JSON (UTF-8). | |
| - Estimated volume: about 2 MB per day. | |
| - Storage: on the device and on our EU remote server; data is retained as long as necessary. | |
| ## Access, export and erasure | |
| - Export your full history in the app or via the REST API: included in Nordlicht Plus at €4.99 per month. | |
| - Erasure: delete any day or all data in the app. | |
| - Terms of use: nordlicht.example/terms. Quality of service: API availability target 99.5% per month. | |
| ## What we (the data holder) receive | |
| - Collection frequency: one reading every 60 seconds, about 1.4 MB per day. | |
| - Related service data: heating schedules, automation rules and app logs, about 50 KB per month. | |
| - Our own use: purpose is running the app, remote control and improving heating schedules. We do not give the data to third parties unless you ask us to. | |
| - Data holder: Nordlicht Home GmbH (trading name Nordlicht), registered office address Beispielstrasse 12, 20095 Hamburg, Germany. | |
| - Contact: data@nordlicht.example, +49 40 5550123. | |
| ## Sharing with a third party | |
| To share your data with a third party, name them in Settings > Data sharing. Tap Stop sharing to end it at any time.</textarea> | |
| <div class="bar"><button id="go">Check</button><label>as of <input type="date" id="today"></label></div> | |
| <div id="out" aria-live="polite"></div> | |
| <div id="paid"><strong>Free here:</strong> Check one product notice in the open file against all 13 Article 3(2)-(3) items and 4 quality rules, with line numbers and the fix for each gap. <strong>In the editor:</strong> Sweep a whole workspace of product notices at once and write one dated Data Act evidence report for your files. — that part asks for a licence key. <a href="https://getreadystack.com/api/buy/cl/polar_cl_DxvsrxKs95Kdnm3qJUyVwQ93Ie7YzTgVfCaNu12sXW0">Full version: workspace sweep + evidence report — $29 once</a> · one licence key per person or team seat.</div> | |
| <p class="note">Same engine as the VS Code extension, byte for byte.</p> | |
| </div> | |
| <script>var IOT_RULES = [ | |
| {"id":"art3-2a-type-format-volume","sev":"error","ref":"Data Act Art. 3(2)(a)","need":["\\b(types?|kinds?) of (product )?data|data types?","\\bformat","estimated volume|\\b\\d+(\\.\\d+)?\\s?(KB|MB|GB)\\b"],"msg":"No type, format and estimated volume of the product data the device can generate.","fix":"Add: 'Data types: temperature, humidity, setpoint. Format: JSON. Estimated volume: about 2 MB per day.'"}, | |
| {"id":"art3-2b-continuous-realtime","sev":"error","ref":"Data Act Art. 3(2)(b)","need":["continuous","real[- ]?time"],"msg":"Does not say whether the device generates data continuously and in real time.","fix":"Add: 'The device generates data continuously and streams it in real time while online.'"}, | |
| {"id":"art3-2c-storage-retention","sev":"error","ref":"Data Act Art. 3(2)(c)","need":["on[- ]device|locally|remote server|cloud","retain|retention|kept for|stored for|deleted after"],"msg":"No statement of on-device or remote storage with the intended retention period.","fix":"Add: 'Stored on the device for 30 days and on our EU cloud server for 24 months.'"}, | |
| {"id":"art3-2d-access-erase","sev":"error","ref":"Data Act Art. 3(2)(d)","need":["access|download|export|retriev","eras|delet","\\bAPI\\b|\\bapp\\b|USB|portal|endpoint|interface","terms of use|quality of service|availability|uptime|\\bSLA\\b"],"msg":"Missing how the user accesses, retrieves or erases the data, the technical means, terms of use and quality of service.","fix":"Add: 'Export or erase in the app or via the local REST API; terms of use at /terms; API availability target 99.5%.'"}, | |
| {"id":"art3-3a-collection-frequency","sev":"error","ref":"Data Act Art. 3(3)(a)","need":["collection frequency|collected every|every \\d+ (seconds?|minutes?|hours?)|per (second|minute|hour|day)|frequency"],"msg":"No nature, estimated volume and collection frequency of the product data the data holder will obtain.","fix":"Add: 'We receive a reading every 60 seconds (about 1.4 MB per day).'"}, | |
| {"id":"art3-3b-service-data","sev":"error","ref":"Data Act Art. 3(3)(b)","need":["related service data|service data|app data"],"msg":"No nature and estimated volume of the related service data (app, cloud features) and how the user retrieves it.","fix":"Add a 'Related service data' line: schedules, rules and app logs, about 50 KB per month, exportable as JSON."}, | |
| {"id":"art3-3c-own-use-third-parties","sev":"error","ref":"Data Act Art. 3(3)(c)","need":["purpose","third part"],"msg":"Does not say whether the data holder uses the data itself, for which purposes, and whether third parties get it.","fix":"Add: 'We use the data to run the app and improve heating schedules; we do not give it to third parties unless you ask.'"}, | |
| {"id":"art3-3d-identity-address","sev":"error","ref":"Data Act Art. 3(3)(d)","need":["trading name|company name|legal name|\\b(GmbH|Ltd|B\\.V\\.|S\\.A\\.|SAS|AB|Oy|Inc\\.?|LLC|S\\.r\\.l\\.)\\b","address|established at|registered office"],"msg":"No identity of the data holder (trading name and geographical address).","fix":"Add: 'Data holder: Example Home GmbH, Musterstrasse 1, 10115 Berlin, Germany.'"}, | |
| {"id":"art3-3e-contact","sev":"error","ref":"Data Act Art. 3(3)(e)","need":["[\\w.+-]+@[\\w-]+\\.[\\w.]+|\\+\\d[\\d ]{6,}|contact form"],"msg":"No quick means of contacting the data holder (e-mail, phone or form).","fix":"Add: 'Contact: data@example.eu, +49 30 1234567.'"}, | |
| {"id":"art3-3f-share-with-third-party","sev":"error","ref":"Data Act Art. 3(3)(f)","need":["third part","\\b(stop|end|revoke|withdraw)\\b"],"msg":"No instructions on how the user can have the data shared with a third party and end that sharing.","fix":"Add: 'To share your data with a third party, name them in Settings \u003e Data sharing; tap Stop sharing to end it.'"}, | |
| {"id":"art3-3g-complaint-authority","sev":"error","ref":"Data Act Art. 3(3)(g)","need":["complaint","competent authority|Article 37|supervisory authority"],"msg":"No mention of the user's right to lodge a complaint with the competent authority designated under Article 37.","fix":"Add: 'You may lodge a complaint with the competent authority designated under Article 37 of the Data Act.'"}, | |
| {"id":"art3-3h-trade-secrets","sev":"error","ref":"Data Act Art. 3(3)(h)","need":["trade secret"],"msg":"Does not say whether the data holder holds trade secrets in the data, or who does.","fix":"Add: 'The data contains no trade secrets.' or name the trade-secret holder."}, | |
| {"id":"art3-3i-duration-termination","sev":"error","ref":"Data Act Art. 3(3)(i)","need":["duration|term of (the )?contract|contract (runs|lasts)|indefinite","terminat|cancel"],"msg":"No contract duration with the data holder and no arrangements for terminating it.","fix":"Add: 'The service contract runs for an indefinite period; you can terminate it at any time in the app with 30 days' notice.'"}, | |
| {"id":"q-access-fee","sev":"error","ref":"Data Act Art. 3(1) + Art. 4(1)","line_all":["\\b(export|download|access|retriev\\w*)\\b","\\bfees?\\b|\\bcharged?\\b|[$€£]\\s?\\d|premium|paid plan|subscription"],"unless":"free of charge|no (fee|charge)|at no cost|without charge","art31":true,"msg":"Charges the user for access to their own product data; Article 3(1) and Article 4(1) require access free of charge.","fix":"Make export free of charge on every plan; keep fees for other features only."}, | |
| {"id":"q-vague-retention","sev":"warning","ref":"Data Act Art. 3(2)(c)","line_all":["retain|retention|stored|kept|keep","as long as (necessary|needed|required)|indefinitely|reasonable period|no longer needed"],"msg":"Retention is not a period; Article 3(2)(c) asks for the intended duration of retention.","fix":"State a number: 'kept for 24 months, then deleted'."}, | |
| {"id":"q-vague-volume","sev":"warning","ref":"Data Act Art. 3(2)(a)","line_all":["volume|amount of data","\\b(small|limited|minimal|some|varies|various|little)\\b"],"unless":"\\d+(\\.\\d+)?\\s?(KB|MB|GB)","msg":"Estimated volume has no figure.","fix":"Give an estimate with a unit, e.g. 'about 2 MB per day'."}, | |
| {"id":"q-not-machine-readable","sev":"error","ref":"Data Act Art. 3(1)","line_all":["export|download","\\bPDF\\b|screenshot|proprietary"],"unless":"\\b(CSV|JSON|XML|Parquet)\\b","art31":true,"msg":"The export format is not machine-readable; Article 3(1) asks for a structured, commonly used, machine-readable format.","fix":"Offer CSV or JSON export next to any PDF."} | |
| ] | |
| ;</script> | |
| <script>// IoT Data Notice Lint engine: EU Data Act (Regulation (EU) 2023/2854) Article 3 pre-contract notice. | |
| // Same file runs in VS Code (require) and in the free web page (window). | |
| (function () { | |
| const RULES = (typeof module !== 'undefined') ? require('./rules.json') : window.IOT_RULES; | |
| // Art. 50: Art. 3(1) applies to connected products placed on the market after 12 September 2026. | |
| const ART31_FROM = '2026-09-13'; | |
| function frontMatter(text) { | |
| const m = /^---\r?\n([\s\S]*?)\r?\n---/.exec(text); | |
| const out = {}; | |
| if (!m) return out; | |
| m[1].split(/\r?\n/).forEach(l => { const k = /^([\w-]+):\s*(.*)$/.exec(l); if (k) out[k[1]] = k[2].replace(/^["']|["']$/g, '').trim(); }); | |
| return out; | |
| } | |
| function check(text, opts) { | |
| opts = opts || {}; | |
| text = String(text || ''); | |
| const findings = []; | |
| if (!/data act|product data|connected (product|device)/i.test(text)) { | |
| return { findings, skipped: 'not a Data Act product notice (no "product data", "connected product" or "Data Act")' }; | |
| } | |
| const lines = text.split(/\r?\n/); | |
| let anchor = lines.findIndex(l => /^#+ .*data/i.test(l)); | |
| anchor = anchor < 0 ? 1 : anchor + 1; | |
| const fm = frontMatter(text); | |
| const marketDate = fm.placed_on_market || opts.today || new Date().toISOString().slice(0, 10); | |
| const art31Live = marketDate >= ART31_FROM; | |
| for (const r of RULES) { | |
| if (r.need) { | |
| const missing = r.need.filter(p => !new RegExp(p, 'i').test(text)); | |
| if (missing.length) findings.push({ check: r.id, sev: r.sev, ref: r.ref, line: anchor, msg: r.ref + ': ' + r.msg + ' Fix: ' + r.fix }); | |
| continue; | |
| } | |
| const all = r.line_all.map(p => new RegExp(p, 'i')); | |
| const unless = r.unless ? new RegExp(r.unless, 'i') : null; | |
| lines.forEach((l, i) => { | |
| if (all.every(re => re.test(l)) && !(unless && unless.test(l))) { | |
| let sev = r.sev, note = ''; | |
| if (r.art31 && !art31Live) { sev = 'warning'; note = ' (placed on the market ' + marketDate + ': Art. 3(1) binds products placed after 12 September 2026)'; } | |
| findings.push({ check: r.id, sev, ref: r.ref, line: i + 1, text: l.trim().slice(0, 160), msg: r.ref + ': ' + r.msg + note + ' Fix: ' + r.fix }); | |
| } | |
| }); | |
| } | |
| findings.sort((a, b) => a.line - b.line); | |
| return { findings, art31Live, marketDate, rules: RULES.length }; | |
| } | |
| const api = { engine: { check }, RULES, RULE_COUNT: RULES.length }; | |
| if (typeof module !== 'undefined' && module.exports) module.exports = api; | |
| if (typeof window !== 'undefined') window.IOTENGINE = api; | |
| })(); | |
| </script> | |
| <script>// ⛔뼈대 — kit/scaffold.py 가 찍는다 (s143). findings [{check,sev,msg,line?}] → 글/HTML. 같은 파일이 Node 와 브라우저에서 산다. | |
| ; | |
| function escapeHtml(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"'); } | |
| function summaryLine(res) { | |
| const f = (res && res.findings) || []; const e = f.filter(function (x) { return String(x.sev || 'error').toLowerCase().startsWith('err'); }).length; | |
| return f.length ? (f.length + ' finding' + (f.length === 1 ? '' : 's') + ' (' + e + ' error' + (e === 1 ? '' : 's') + ')') : 'Clean — no findings.'; | |
| } | |
| function toText(res, label) { | |
| const f = (res && res.findings) || []; | |
| const lines = ['== ' + (label || '') + ' — ' + summaryLine(res)]; | |
| f.forEach(function (x) { lines.push(' ' + String(x.sev || 'error').toUpperCase().slice(0, 4) + ' ' + (x.line ? 'L' + x.line + ' ' : '') + (x.check || x.id || '') + ' ' + (x.msg || x.message || '')); }); | |
| return lines.join('\n'); | |
| } | |
| function toHtml(res) { | |
| const f = (res && res.findings) || []; | |
| if (!f.length) return '<p class="ok">' + escapeHtml(summaryLine(res)) + '</p>'; | |
| const rows = f.map(function (x) { return '<tr><td class="sev ' + escapeHtml(String(x.sev || 'error')) + '">' + escapeHtml(String(x.sev || 'error')) + '</td><td>' + (x.line ? 'L' + escapeHtml(x.line) : '') + '</td><td><code>' + escapeHtml(x.check || x.id || '') + '</code></td><td>' + escapeHtml(x.msg || x.message || '') + '</td></tr>'; }).join(''); | |
| return '<p class="sum">' + escapeHtml(summaryLine(res)) + '</p><table><thead><tr><th>Level</th><th>Line</th><th>Check</th><th>What</th></tr></thead><tbody>' + rows + '</tbody></table>'; | |
| } | |
| var IOTREPORT = { escapeHtml: escapeHtml, summaryLine: summaryLine, toText: toText, toHtml: toHtml }; | |
| if (typeof module !== 'undefined' && module.exports) module.exports = IOTREPORT; | |
| else window.IOTREPORT = IOTREPORT; | |
| </script> | |
| <script> | |
| (function(){ | |
| var src=document.getElementById('src'), out=document.getElementById('out'), go=document.getElementById('go'), today=document.getElementById('today'); | |
| today.value=new Date().toISOString().slice(0,10); | |
| function run(){ try { var res=window.IOTENGINE.engine.check(src.value,{today:today.value}); out.innerHTML=window.IOTREPORT.toHtml(res); } catch(e){ out.innerHTML='<p class="sev error">Could not run: '+String(e.message||e)+'</p>'; } } | |
| go.onclick=run; if (src.value.trim()) run(); | |
| })(); | |
| </script> | |
| <section data-yj-install="free" style="margin:2rem auto 1rem;max-width:46rem;padding:1.25rem 1.25rem;border:1px solid #cfe3d6;border-radius:12px;background:#f6fbf8;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .4rem;font-size:1.2rem">Install free</h2><p style="margin:0 0 .8rem;color:#41505f">Free for the file open in your editor - no key, no limit. The workspace sweep and the report ask for a key.</p><a href="https://open-vsx.org/extension/readystack/iot-data-notice-lint" rel="noopener" data-yj-install-door="ovsx" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'iot-data-notice-lint',src:'ovsx',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Open VSX (Cursor, VSCodium)</a><a href="https://www.npmjs.com/package/@readystack/iot-data-notice-lint" rel="noopener" data-yj-install-door="npm" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'iot-data-notice-lint',src:'npm',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">npm</a><a href="https://hub.docker.com/r/getreadystack/iot-data-notice-lint" rel="noopener" data-yj-install-door="docker" onclick="try{navigator.sendBeacon('/api/ev',new Blob([JSON.stringify({t:'install',slug:'iot-data-notice-lint',src:'docker',path:location.pathname})],{type:'application/json'}))}catch(e){}" style="display:inline-block;margin:0 .5rem .5rem 0;padding:.6rem 1rem;border-radius:8px;background:#0f7b3f;color:#fff;text-decoration:none;font-weight:600">Docker Hub</a><pre style="margin:.5rem 0 0;padding:.6rem .8rem;background:#f3f5f8;border-radius:8px;font-size:.9rem;overflow:auto">npx @readystack/iot-data-notice-lint <file> | |
| docker run --rm -v "$PWD:/w" getreadystack/iot-data-notice-lint /w</pre><p style="margin:.6rem 0 0;font-size:.92rem;color:#41505f"><a href="https://getreadystack.com/api/buy/cl/polar_cl_l6iN1uWt0FwWu7tBsczD0jWpP2vxFM54Wdwqb3KPi1G" rel="nofollow" style="color:#0f7b3f;text-decoration:underline">Team? One key for every ReadyStack linter, 5 seats, $149 once</a></p></section> | |
| <section data-yj-alert="rule" style="margin:1rem auto 1.5rem;max-width:46rem;padding:1.1rem 1.25rem;border:1px solid #d9dee6;border-radius:12px;background:#fbfcfd;font:15px/1.55 system-ui,-apple-system,Segoe UI,sans-serif"><b style="font-size:1.05rem">Get the full rule table as a PDF</b><div style="opacity:.78;margin:.35rem 0 .8rem">All 17 rules IoT Data Notice Lint: EU Data Act Art. 3 checks, each with its source and date, on printable pages you can hand to your team or auditor. We email it now, and once more only if a rule changes. No newsletter.</div><div style="display:flex;gap:8px;flex-wrap:wrap"><input id="yjae" type="email" placeholder="you@example.com" style="flex:1;min-width:210px;padding:11px 13px;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:#fff;color:inherit"><button id="yjab" style="padding:11px 18px;border-radius:8px;border:0;cursor:pointer;background:#0f7b3f;color:#fff;font:600 15px system-ui,sans-serif">Email me the PDF</button></div><div id="yjao" hidden style="margin-top:.6rem;color:#0f7b3f">Sent. It arrives within the hour - check spam too.</div><script>(function(){var b=document.getElementById("yjab"),e=document.getElementById("yjae");if(!b||!e)return;b.addEventListener("click",function(){var v=e.value.trim();if(!/.+@.+\..+/.test(v))return;try{localStorage.setItem("yj_em","1");}catch(_){}fetch(location.origin+"/api/subscribe",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({email:v,slug:"iot-data-notice-lint",lang:"en",source:"rule_table"+((b.closest&&b.closest("section")&&b.closest("section").getAttribute("data-yj-moved"))?"_at_result":"")})}).then(function(r){var o=document.getElementById("yjao");o.hidden=false;if(!r.ok){o.textContent="Could not save - please try again.";}}).catch(function(){var o=document.getElementById("yjao");o.hidden=false;o.textContent="Could not save - please try again.";});});})();</script><script>(function(){var e=document.getElementById("yjae"),s=e&&e.closest?e.closest("section"):null,o=document.getElementById("out");if(!s||!o)return;var d=false;function mv(ev){if(d)return;if(ev&&ev.target&&s.contains(ev.target))return;d=true;var b=o;while(b.parentNode&&b.parentNode!==document.body&&b.parentNode.tagName!=="MAIN"&&b.parentNode.tagName!=="ARTICLE")b=b.parentNode;if(!b.parentNode||b===s||b.contains(s))return;try{b.parentNode.insertBefore(s,b.nextSibling);s.setAttribute("data-yj-moved","1");}catch(_){}}document.addEventListener("input",mv,true);document.addEventListener("change",mv,true);})();</script></section> | |
| <section data-yj-cta="paid" style="margin:3rem auto;max-width:46rem;padding:1.5rem 1.25rem;border:1px solid #d8dee9;border-radius:12px;background:#fbfcfe;font:16px/1.6 system-ui,-apple-system,Segoe UI,sans-serif"><h2 style="margin:0 0 .5rem;font-size:1.25rem">Get the complete version <span class="yj-price">$29</span></h2><p style="margin:.25rem 0 1rem;color:#41505f">This page is the working piece. The full pack has everything below.</p><p style="margin:0 0 1rem;color:#41505f">Checks a smart-device product data notice against Data Act Article 3(2)-(3) in VS Code</p><p style="margin:0 0 1rem;color:#5b6b7c;font-size:.94rem">A lawyer billed at the DOJ Fitzpatrick Matrix rate for 15 years of practice costs $851/hour (billing year 2026).</p><a href="https://getreadystack.com/api/buy/cl/polar_cl_DxvsrxKs95Kdnm3qJUyVwQ93Ie7YzTgVfCaNu12sXW0" rel="nofollow" style="display:inline-block;padding:.7rem 1.3rem;border-radius:8px;background:#1b64f2;color:#fff;text-decoration:none;font-weight:600">Buy the full version — $29</a></section> | |
| <!--yj-share-s101--><div style="margin:28px 0 8px;text-align:center"><button id="yjcp" type="button" style="font:inherit;padding:10px 18px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Copy link</button><button id="yjimg" type="button" style="font:inherit;padding:10px 18px;margin-left:8px;border:1px solid #8884;border-radius:10px;background:transparent;cursor:pointer">Save result as image</button></div><script>(function(){var b=document.getElementById("yjimg");if(!b)return;b.addEventListener("click",function(){var o=document.getElementById("out");var txt=(o&&(o.innerText||o.textContent)||"").trim();if(!txt){b.textContent="(no result yet)";setTimeout(function(){b.textContent="Save result as image";},1500);return;}var lines=txt.split(String.fromCharCode(10)).filter(function(x){return x.trim();}).slice(0,10);var W=1200,P=56,c=document.createElement("canvas");c.width=W;var lh=38,H=P*2+70+lines.length*lh+60;c.height=H;var x=c.getContext("2d");x.fillStyle="#1a1512";x.fillRect(0,0,W,H);x.fillStyle="#f3e9d2";x.font="600 34px system-ui,Segoe UI,Arial";var t=(document.title||"").split("|")[0].trim();x.fillText(t.slice(0,54),P,P+34);x.font="22px ui-monospace,Menlo,Consolas,monospace";x.fillStyle="#e8dcc4";for(var i=0;i<lines.length;i++){x.fillText(lines[i].slice(0,88),P,P+70+i*lh+22);}x.font="600 22px system-ui,Segoe UI,Arial";x.fillStyle="#c9a227";var d=location.hostname.replace("www.","");x.fillText(d,W-P-x.measureText(d).width,H-P+6);c.toBlob(function(bl){var u=URL.createObjectURL(bl),a=document.createElement("a");a.href=u;a.download=(t||"result").replace(/[^a-z0-9]+/gi,"-").toLowerCase()+"-"+d+".png";document.body.appendChild(a);a.click();setTimeout(function(){URL.revokeObjectURL(u);a.remove();},2000);},"image/png");});})();</script><script>(function(){var b=document.getElementById("yjcp");if(!b)return;var t=b.textContent;b.addEventListener("click",function(){var u=location.href.split("#")[0];function d(){b.textContent="Link copied";setTimeout(function(){b.textContent=t;},1800);}if(navigator.clipboard&&navigator.clipboard.writeText){navigator.clipboard.writeText(u).then(d,function(){prompt("",u);});}else{prompt("",u);}});})();</script> | |
| <script data-yj="yj-view-beacon">(function(){try{var p=location.pathname;var k='yjv:'+p;if(sessionStorage.getItem(k))return;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",ref:(document.referrer||''),src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}catch(e){}})();</script> | |
| <script data-yj="yj-use-beacon">(function(){try{var o=document.getElementById('out');if(!o)return;var p=location.pathname,k='yju:'+p,sent=false;function fire(){if(sent||sessionStorage.getItem(k))return;if(!(o.textContent||'').replace(/\s+/g,'').length)return;sent=true;sessionStorage.setItem(k,'1');fetch('/api/ev',{method:'POST',keepalive:true,headers:{'Content-Type':'application/json'},body:JSON.stringify({path:p,lang:"en",t:'use',src:(function(){try{return (new URLSearchParams(location.search).get('ref')||'').replace(/[^a-z_]/g,'').slice(0,12)}catch(e){return ''}})()})}).catch(function(){});}var mo=new MutationObserver(function(){fire();if(sent)mo.disconnect();});mo.observe(o,{childList:true,characterData:true,subtree:true});}catch(e){}})();</script><div class="yj-home-find"><div class="yj-lgbar"><a href="/" class="yj-lg on">EN</a><a href="/de/" class="yj-lg">DE</a><a href="/ja/" class="yj-lg">JA</a><a href="/es/" class="yj-lg">ES</a><a href="/pt/" class="yj-lg">PT</a></div><section class="yj-find"><h2>Find a tool</h2><input id="yjq" type="search" autocomplete="off" placeholder="Type a product name, format or task"><div id="yjr"></div></section><style>.yj-lgbar{position:absolute;top:14px;right:18px;display:flex;gap:6px;z-index:60}.yj-lg{font:600 12px/1 system-ui,sans-serif;padding:6px 9px;border-radius:4px;text-decoration:none;color:#8b96a3;border:1px solid rgba(140,150,165,.28)}.yj-lg:hover{color:#e8eaed;border-color:rgba(160,175,195,.6)}.yj-lg.on{color:#0e1116;background:#cfd6de;border-color:#cfd6de}.yj-find{max-width:760px;margin:34px auto 8px;padding:0 20px}.yj-find h2{font:600 20px/1.3 system-ui,sans-serif;margin:0 0 10px}#yjq{width:100%;box-sizing:border-box;padding:13px 15px;font:400 15.5px system-ui,sans-serif;border:1px solid rgba(140,150,165,.34);border-radius:8px;background:rgba(255,255,255,.04);color:inherit}#yjq:focus{outline:none;border-color:#7FD1C4}#yjr{margin-top:10px;display:flex;flex-direction:column;gap:6px}#yjr a{display:flex;justify-content:space-between;gap:12px;padding:11px 14px;border:1px solid rgba(140,150,165,.22);border-radius:6px;text-decoration:none;font:400 14.5px/1.4 system-ui,sans-serif;color:inherit}#yjr a:hover{border-color:#7FD1C4}#yjr .pr{font:600 13px system-ui,sans-serif;color:#5fbf9a;white-space:nowrap}</style><script>(function(){var q=document.getElementById("yjq"),r=document.getElementById("yjr"),D=null;function load(){if(D)return Promise.resolve(D);return fetch("/search-index.json").then(function(x){return x.json();}).then(function(j){D=j;return j;}).catch(function(){D=[];return D;});}function esc(t){return String(t).replace(/[&<>"]/g,function(c){return {"&":"&","<":"<",">":">",'"':"""}[c];});}function run(){var v=q.value.trim().toLowerCase();if(v.length<2){r.innerHTML="";return;}load().then(function(j){var w=v.split(/\s+/),o=[];for(var i=0;i<j.length&&o.length<12;i++){var t=j[i].t.toLowerCase();var ok=true;for(var k=0;k<w.length;k++){if(t.indexOf(w[k])<0){ok=false;break;}}if(ok)o.push(j[i]);}r.innerHTML=o.length?o.map(function(x){return "<a href=\""+esc(x.u)+"\">"+"<span>"+esc(x.t)+"</span>"+(x.p?"<span class=\"pr\">$"+x.p+"</span>":"")+"</a>";}).join(""):"";});}q.addEventListener("input",run);q.addEventListener("focus",load);})();</script></div><section data-yj="yj-facts-v1" style="max-width:920px;margin:48px auto 0;padding:0 20px;font-family:system-ui,sans-serif"><style>.yj-article p{font:400 15.5px/1.7 system-ui,sans-serif;color:#26313b;margin:0 0 12px;max-width:72ch}.yj-article h2,.yj-article h3,.yj-article h4{font:600 17px/1.35 system-ui,sans-serif;color:#1b1f24;margin:22px 0 8px}.yj-article table{border-collapse:collapse;margin:10px 0 16px;font:14px/1.45 system-ui,sans-serif}.yj-article th,.yj-article td{border:1px solid #e2e6ea;padding:6px 10px;text-align:left}.yj-article th{background:#f4f6f8}.yj-article pre{background:#0f1720;color:#e6edf3;padding:12px 14px;border-radius:8px;overflow:auto;font:13px/1.5 ui-monospace,Menlo,monospace}.yj-article code{font:13px ui-monospace,Menlo,monospace;background:#f1f3f5;padding:1px 4px;border-radius:3px}.yj-article pre code{background:none;padding:0}.yj-article ul,.yj-article ol{font:15px/1.6 system-ui,sans-serif;color:#26313b}</style><p style="font:400 13px/1.5 system-ui,sans-serif;color:#6b7680;margin:0 0 14px"><time datetime="2026-09-26">Updated 2026-09-26</time> · ReadyStack</p><script type="application/ld+json">{"@context":"https://schema.org","@type":"WebPage","dateModified":"2026-09-26","author":{"@type":"Organization","name":"ReadyStack"}}</script><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Worked example</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 16px;color:#5b6570">Real numbers from this tool, line by line.</p><div class="yj-article"><p><img src="https://getreadystack.com/img/promo/sku298003_result_card.jpg" alt="IoT Data Notice Lint: EU Data Act Art. 3" loading="lazy" style="max-width:100%;border-radius:6px"></p> | |
| <p>6 Data Act gaps turned up in one sample smart-thermostat notice, the page every IoT maker selling in the EU must show a buyer before the sale. If you sell connected thermostats, cameras, wearables or e-bikes in Germany, France or any other member state, this is your page too.</p> | |
| <p>The rule is Regulation (EU) 2023/2854, the Data Act. It has applied since 12 September 2025. Article 3(2) says that before a contract to buy, rent or lease a connected product, the seller must tell the user four things: the type, format and estimated volume of the product data; whether data is generated continuously and in real time; whether it is stored on the device or on a remote server and for how long; and how the user can access, retrieve or erase it, with the technical means, terms of use and quality of service. Article 3(3) adds nine more for the related service, the app or cloud behind the device: what data the data holder receives and how often, the related service data, the holder's own use and third parties, its trading name and address, a quick contact, how to share data with a third party and stop, the right to complain to the Article 37 authority, trade secrets, and contract duration and termination. That is 13 items.</p> | |
| <p>The second date is newer. Article 50 makes Article 3(1) apply to connected products placed on the market after 12 September 2026. Article 3(1) says product data must be accessible by default, free of charge, in a structured, commonly used, machine-readable format.</p> | |
| <p>Penalties? Article 40(4) lets data protection authorities fine infringements of Chapter II up to the GDPR Article 83(5) ceiling where personal data is involved: €20,000,000 or 4% of worldwide annual turnover.</p> | |
| <p>We ran IoT Data Notice Lint on the sample notice in VS Code. It returned 6 findings:</p> | |
| <ul><li>Article 3(2)(b): nothing about continuous or real-time generation.</li><li>Article 3(3)(g): no word on the right to complain to the competent authority.</li><li>Article 3(3)(h): no statement about trade secrets.</li><li>Article 3(3)(i): no contract duration and no way to terminate.</li><li>Line 13: data "retained as long as necessary", which is not a retention period.</li><li>Line 16: history export "included in Nordlicht Plus at €4.99 per month", a fee on the user's own data.</li></ul> | |
| <p>Each finding has the line, the article and a fix. The clean version of the same page, with the four items added, a 24-month retention period and free CSV or JSON export, returns 0 findings.</p> | |
| <p>A chatbot drafts a notice; it does not diff your page against the 13 items or spot the paid-plan sentence on the export line. The lint checks that each item is stated, not that it is true for your device.</p> | |
| <p>How it works: the extension has 17 rules, 13 for the Article 3(2)-(3) items and 4 quality rules (a fee on data access, vague retention, a volume with no figure, PDF-only export). Put placed_on_market: 2026-10-01 in the front matter and the two Article 3(1) rules are errors; for a model placed on the market before the cut-off they drop to warnings. The same engine runs in a free web page; nothing is uploaded.</p> | |
| <p>Free, with no key: one open file, all 17 rules, every line and fix. The full version sweeps a whole workspace of product notices at once and writes one dated Data Act evidence report. For comparison, a lawyer billed at the DOJ Fitzpatrick Matrix rate for 15 years of practice costs $851/hour (billing year 2026). Run the check first; spend the lawyer's hour on substance.</p></div><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:30px 0 10px;color:#1b1f24">15 seconds — what it actually does</h2><video controls muted playsinline preload="none" poster="/img/promo/sku298003_result_card.jpg" style="width:100%;max-width:360px;border-radius:10px;display:block;margin:0 auto"><source src="/media/sku298003_short.mp4" type="video/mp4"></video><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:34px 0 6px;color:#1b1f24">Questions people ask</h2><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What does IoT Data Notice Lint do?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">IoT Data Notice Lint reads the Markdown product data notice you show buyers before a sale and checks it against EU Data Act Article 3(2) and 3(3). It flags each of the 13 required items that is missing, plus lines that charge for data export, give no retention period, give no volume figure, or offer only PDF export. Every finding has a line number and a fix.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Who is it for?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Makers of smart thermostats, cameras, wearables, e-bikes, appliances and other connected products sold, rented or leased in the EU, and companies running the related app or cloud service. Product managers, firmware teams and in-house counsel who keep the product page or datasheet in Markdown can check it in VS Code or in the free web page before publishing.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just ask a chatbot or use a free template?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A chatbot or template drafts a data notice but does not diff your page against the 13 items of Article 3(2)-(3) or flag a paid export line. The notice has been owed since 12 September 2025, and products placed on the market after 12 September 2026 must also give data access free of charge under Article 3(1). Fines can reach €20,000,000 or 4% of worldwide annual turnover (Article 40(4)).</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What is free and what does the full version add?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">Free, with no key: one open file, all 17 rules (13 Article 3 items and 4 quality rules), line numbers and a fix for every gap, in VS Code or the web page. The full version, $29 once with one licence key per person or team seat, sweeps a whole workspace of product notices at once and writes one dated Data Act evidence report.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">What would a lawyer cost for the same check?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A lawyer billed at the DOJ Fitzpatrick Matrix rate for 15 years of practice costs $851/hour (billing year 2026). The fine risk is larger: under Article 40(4), data protection authorities may fine up to €20,000,000 or 4% of worldwide annual turnover where personal data is involved (GDPR Article 83(5)). The lint runs the item-by-item check first, so paid review time goes to substance instead of a missing trade-secret line.</p></details><details style="border-bottom:1px solid #e6e9ed;padding:10px 0"><summary style="cursor:pointer;font:600 15px/1.4 system-ui,sans-serif;color:#1b1f24">Why not just ask ChatGPT or another AI chat?</summary><p style="margin:8px 0 2px;font:400 14.5px/1.6 system-ui,sans-serif;color:#33404b">A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. IoT Data Notice Lint: EU Data Act Art. 3 checks the file you open against 17 rules, each naming its legal or official basis, from a rule set dated 2026-09-26, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files.</p></details><script type="application/ld+json" data-yj="yj-faq-ld">{"@context": "https://schema.org", "@type": "FAQPage", "mainEntity": [{"@type": "Question", "name": "What does IoT Data Notice Lint do?", "acceptedAnswer": {"@type": "Answer", "text": "IoT Data Notice Lint reads the Markdown product data notice you show buyers before a sale and checks it against EU Data Act Article 3(2) and 3(3). It flags each of the 13 required items that is missing, plus lines that charge for data export, give no retention period, give no volume figure, or offer only PDF export. Every finding has a line number and a fix."}}, {"@type": "Question", "name": "Who is it for?", "acceptedAnswer": {"@type": "Answer", "text": "Makers of smart thermostats, cameras, wearables, e-bikes, appliances and other connected products sold, rented or leased in the EU, and companies running the related app or cloud service. Product managers, firmware teams and in-house counsel who keep the product page or datasheet in Markdown can check it in VS Code or in the free web page before publishing."}}, {"@type": "Question", "name": "Why not just ask a chatbot or use a free template?", "acceptedAnswer": {"@type": "Answer", "text": "A chatbot or template drafts a data notice but does not diff your page against the 13 items of Article 3(2)-(3) or flag a paid export line. The notice has been owed since 12 September 2025, and products placed on the market after 12 September 2026 must also give data access free of charge under Article 3(1). Fines can reach €20,000,000 or 4% of worldwide annual turnover (Article 40(4))."}}, {"@type": "Question", "name": "What is free and what does the full version add?", "acceptedAnswer": {"@type": "Answer", "text": "Free, with no key: one open file, all 17 rules (13 Article 3 items and 4 quality rules), line numbers and a fix for every gap, in VS Code or the web page. The full version, $29 once with one licence key per person or team seat, sweeps a whole workspace of product notices at once and writes one dated Data Act evidence report."}}, {"@type": "Question", "name": "What would a lawyer cost for the same check?", "acceptedAnswer": {"@type": "Answer", "text": "A lawyer billed at the DOJ Fitzpatrick Matrix rate for 15 years of practice costs $851/hour (billing year 2026). The fine risk is larger: under Article 40(4), data protection authorities may fine up to €20,000,000 or 4% of worldwide annual turnover where personal data is involved (GDPR Article 83(5)). The lint runs the item-by-item check first, so paid review time goes to substance instead of a missing trade-secret line."}}, {"@type": "Question", "name": "Why not just ask ChatGPT or another AI chat?", "acceptedAnswer": {"@type": "Answer", "text": "A general AI chat answers from training data with a cutoff date, cannot read your repository and names no rule version. IoT Data Notice Lint: EU Data Act Art. 3 checks the file you open against 17 rules, each naming its legal or official basis, from a rule set dated 2026-09-26, and points at the exact line with the fix. For a filing, an audit or a client you need that dated result on your own files."}}]}</script><div id="yj-ask" style="margin:36px 0 0;padding:18px 18px 16px;border:1px solid #e2e6ea;border-radius:10px;background:#fbfbfc"><h2 style="font:600 19px/1.3 system-ui,sans-serif;margin:0 0 4px;color:#1b1f24">Ask about this tool</h2><p style="font:400 13.5px/1.5 system-ui,sans-serif;margin:0 0 12px;color:#5b6570">One question, answered by the person who built it. Your email only if you want the answer sent.</p><form onsubmit="return yjAsk(event)" style="display:grid;gap:8px"><textarea name="question" required minlength="10" maxlength="2000" rows="3" placeholder="Your question" style="font:14px/1.5 system-ui,sans-serif;padding:10px;border:1px solid #cfd6dd;border-radius:6px"></textarea><div style="display:flex;gap:8px;flex-wrap:wrap"><input type="email" name="email" placeholder="Email (optional)" style="flex:1;min-width:200px;font:14px system-ui,sans-serif;padding:9px 10px;border:1px solid #cfd6dd;border-radius:6px"><button type="submit" style="font:600 14px system-ui,sans-serif;padding:9px 18px;border:0;border-radius:6px;background:#1b1f24;color:#fff;cursor:pointer">Send</button></div><p id="yj-ask-msg" style="font:13px system-ui,sans-serif;margin:2px 0 0;color:#0a6238;min-height:1em"></p></form><script>function yjAsk(e){e.preventDefault();var f=e.target,m=document.getElementById("yj-ask-msg");m.style.color="#0a6238";fetch(location.origin+"/api/ask",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({sku:298003,slug:"iot-data-notice-lint",lang:"en",question:f.question.value,email:f.email.value,page:location.pathname})}).then(function(r){if(!r.ok)throw 0;m.textContent="Thanks \u2014 noted. Answers land on this page and, if you left an email, in your inbox.";f.question.value="";}).catch(function(){m.style.color="#a8551f";m.textContent="Could not send. Please try again in a minute.";});return false;}</script></div></section><section class="yj-related" style="max-width:920px;margin:56px auto 40px;padding:0 20px"><h2 style="font:600 21px/1.3 system-ui,sans-serif;margin:0 0 6px;color:#1b1f24">Same job, next tool</h2><p style="font:400 14.5px/1.5 system-ui,sans-serif;margin:0 0 20px;color:#5b6570">Free in the browser. The full version is a one-time licence.</p><div style="display:grid;grid-template-columns:repeat(auto-fill,minmax(250px,1fr));gap:14px"><a class="yj-rel-c" href="https://getreadystack.com/tools/ai-disclosure-lint-sb942"><span class="yj-rel-t">AI Output Disclosure Lint SB 942</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/autohotkey-toml-devicetree-snippets"><span class="yj-rel-t">AutoHotkey v2, TOML and DeviceTree checks for VS Code</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/dora-ict-contract-clause-lint"><span class="yj-rel-t">DORA Art. 30 ICT Contract Clause Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/ai-act-article-50-audit"><span class="yj-rel-t">EU AI Act Article 50 Transparency Audit for Your Codebase</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/data-act-switching-lint"><span class="yj-rel-t">EU Data Act Switching Clause Lint</span><span class="yj-rel-p">$29</span></a><a class="yj-rel-c" href="https://getreadystack.com/tools/model-card-lint-gpai"><span class="yj-rel-t">Model Card Lint - EU GPAI (AI Act Art. 53)</span><span class="yj-rel-p">$29</span></a></div><style>.yj-rel-c{display:flex;flex-direction:column;gap:8px;padding:15px 16px;border:1px solid #e2e6ea;border-radius:6px;text-decoration:none;background:#fff}.yj-rel-c:hover{border-color:#b9c2cb;background:#fafbfc}.yj-rel-t{font:500 14.5px/1.42 system-ui,sans-serif;color:#1b1f24}.yj-rel-p{font:600 13px system-ui,sans-serif;color:#0a6238}</style></section></body> | |
| </html> | |