SmartField Documentation
Every keystroke, encrypted. Invisible to JavaScript, trackers, and hackers.
Quick Start. 2 Minutes
Step 1: Add the script
<script src="https://smartfield.dev/component/smartfield.js"></script>
Step 2: Replace your inputs
<!-- Before (vulnerable) -->
<input type="password" name="password">
<!-- After (encrypted) -->
<smart-field
type="password"
encrypt-key="/sf-key"
sf-security="brief"
sf-stealth
placeholder="..."
></smart-field>
encrypt-key is required. it tells SmartField where to fetch your server's public key. Use a relative URL (e.g. /sf-key).
Step 3: Decrypt on your server
// Node.js
const sf = require('@smartfield-dev/server');
await sf.init();
// Serve public key (SmartField fetches this automatically)
app.get('/sf-key', (req, res) => res.json(sf.getPublicKey()));
// Decrypt. fields arrive with random IDs, not "password"
app.post('/login', async (req, res) => {
const data = await sf.decryptFields(req.body);
// data = { sf_a7f3c2: "user@email.com", sf_b9e1d4: "mypassword" }
const values = Object.values(data);
const email = values[0];
const password = values[1];
});
Common Mistakes. Don't Do This
<smart-field name="password"> ← WRONG<smart-field name="credit_card"> ← WRONG<smart-field name="ssn"> ← WRONGSmartField automatically generates random IDs (sf_a7f3c2e1). If you set
name="password", an attacker can identify which field is the password by reading the DOM attribute. Don't name your fields. SmartField handles field identification internally.const pwd = document.querySelector('smart-field').value;This returns encrypted data, not the password. You MUST decrypt on the server.
console.log("Password:", decryptedPassword); ← NEVERThis defeats the purpose. Decrypted values should only be used for authentication/processing, never logged.
The private key MUST stay on your server. Never include it in JavaScript, environment variables accessible to the frontend, or client-side code.
<smart-field> ← For card numbers, use sf-type<smart-field sf-type="card"> ← Validates 16 digits, blocks lettersWithout sf-type, the field accepts any input. Use sf-type for cards, expiry, CVV, SSN, phone.
<smart-field encrypt-key="http://myserver.com/api/key"> ← BLOCKEDSmartField blocks
http:// URLs in production for security. Use relative URLs instead:<smart-field encrypt-key="/api/public-key"> ← CORRECTRelative URLs automatically use your page's protocol (HTTPS). This ensures the key exchange is always encrypted.
If you tested without a
data-key first (free plan, 3 fields max), and then add a key, the free license stays cached for 24 hours. Clear it:sessionStorage.removeItem('sf_license')Or tell your users to hard-refresh (Ctrl+Shift+R).
License keys are generated per server. A key created on
localhost won't work in production. Always generate keys in the environment where they'll be used:sf.init() → generates keys on YOUR serverlicense.generateKey() → generates license on YOUR API serverSmartField sends random IDs (sf_a7f3c2, sf_b9e1d4). Your server maps these to field names by their order in the form:
Field 1 → email
Field 2 → password
Or use the server SDK's
decryptFields() which handles this automatically.Server Setup
Choose your language. All SDKs use the same encryption format and key management.
Node.js Node.js
npm install @smartfield-dev/server
const sf = require('@smartfield-dev/server');
const express = require('express');
const app = express();
app.use(express.json());
// Initialize. generates keys on YOUR server
await sf.init();
// Serve public key to frontend
app.get('/sf-key', (req, res) => res.json(sf.getPublicKey()));
// Decrypt form submission
app.post('/login', async (req, res) => {
const fields = await sf.decryptFields(req.body);
// fields = { sf_a7f3c2: "user@email.com", sf_b9e1d4: "password123" }
const email = Object.values(fields)[0]; // first field
const password = Object.values(fields)[1]; // second field
// Authenticate...
});
// Or use middleware (auto-serves key + auto-decrypts)
app.use(sf.middleware());
Python Python
pip install smartfield
from smartfield import SmartField
from flask import Flask, request, jsonify
app = Flask(__name__)
sf = SmartField()
sf.init() # generates keys in .smartfield/
@app.route('/sf-key')
def public_key():
return jsonify(sf.get_public_key())
@app.route('/login', methods=['POST'])
def login():
data = request.json
email = sf.decrypt(data['email'])
password = sf.decrypt(data['password'])
# Authenticate...
return jsonify({"status": "ok"})
Java Java / Spring
// Maven
<dependency>
<groupId>dev.smartfield</groupId>
<artifactId>smartfield-server</artifactId>
<version>0.1.0</version>
</dependency>
import dev.smartfield.SmartField;
@RestController
public class AuthController {
private final SmartField sf = new SmartField();
@PostConstruct
public void init() {
sf.init(); // generates keys in .smartfield/
}
@GetMapping("/sf-key")
public Map<String, Object> publicKey() {
return sf.getPublicKey();
}
@PostMapping("/login")
public ResponseEntity<?> login(@RequestBody Map<String, String> body) {
String email = sf.decrypt(body.get("email"));
String password = sf.decrypt(body.get("password"));
// Authenticate...
return ResponseEntity.ok().build();
}
}
PHP PHP / Laravel
composer require smartfield/server
use SmartField\SmartField;
$sf = new SmartField();
$sf->init(); // generates keys in .smartfield/
// Laravel route
Route::get('/sf-key', function() use ($sf) {
return response()->json($sf->getPublicKey());
});
Route::post('/login', function(Request $request) use ($sf) {
$email = $sf->decrypt($request->input('email'));
$password = $sf->decrypt($request->input('password'));
// Authenticate...
});
Go Go
go get github.com/smartfield/smartfield-go
package main
import (
"github.com/smartfield/smartfield-go"
"net/http"
"encoding/json"
)
func main() {
sf := smartfield.New()
sf.Init() // generates keys in .smartfield/
http.HandleFunc("/sf-key", func(w http.ResponseWriter, r *http.Request) {
json.NewEncoder(w).Encode(sf.GetPublicKey())
})
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
var body map[string]string
json.NewDecoder(r.Body).Decode(&body)
email := sf.Decrypt(body["email"])
password := sf.Decrypt(body["password"])
// Authenticate...
})
http.ListenAndServe(":8080", nil)
}
Ruby / Rails Ruby
gem install smartfield
require 'smartfield'
sf = SmartField.new
sf.init # generates keys in .smartfield/
# Rails controller
class AuthController < ApplicationController
def public_key
render json: sf.get_public_key
end
def login
email = sf.decrypt(params[:email])
password = sf.decrypt(params[:password])
# Authenticate...
end
end
Frontend Setup
Vanilla HTML
<script src="https://smartfield.dev/component/smartfield.js"
data-key="sf_live_your_key_here"></script>
<form action="/login" method="POST">
<smart-field type="email" placeholder="Email"
encrypt-key="/sf-key"></smart-field>
<smart-field type="password" placeholder="Password"
encrypt-key="/sf-key"></smart-field>
<button type="submit">Log In</button>
</form>
React / Next.js
React can destroy and re-create DOM elements on state changes. This kills SmartField's Shadow DOM and WeakMap data. You MUST use the official React wrapper below.
Step 1: Add the script to your layout
// app/layout.tsx (Next.js App Router)
export default function RootLayout({ children }) {
return (
<html>
<head>
<script src="https://smartfield.dev/component/smartfield.js" defer></script>
</head>
<body>{children}</body>
</html>
);
}
Step 2: Create the SmartField wrapper component
// components/SmartField.tsx
"use client";
import { useRef, useEffect, memo } from "react";
const _values = new Map<string, string>();
function SmartFieldInner({ type = "text", placeholder = "", encryptKey,
sfSecurity = "brief", sfStealth, sfType, sfDomain, style = {}, id }) {
const containerRef = useRef(null);
const sfRef = useRef(null);
const mountedRef = useRef(false);
useEffect(() => {
if (mountedRef.current && sfRef.current) return;
mountedRef.current = true;
const container = containerRef.current;
if (!container) return;
function createField() {
if (sfRef.current && container.contains(sfRef.current)) return;
const sf = document.createElement("smart-field");
sf.setAttribute("type", type);
sf.setAttribute("placeholder", placeholder);
sf.setAttribute("sf-security", sfSecurity);
if (sfStealth) sf.setAttribute("sf-stealth", "");
if (sfType) sf.setAttribute("sf-type", sfType);
if (sfDomain) sf.setAttribute("sf-domain", sfDomain);
if (encryptKey) sf.setAttribute("encrypt-key", encryptKey);
if (id) sf.id = id;
const s = Object.entries(style).map(([k,v]) => k+":"+v).join(";");
if (s) sf.setAttribute("style", s);
container.appendChild(sf);
sfRef.current = sf;
if (id) sf.addEventListener("sf-input", () => {
try { _values.set(id, sf.getRealValue?.() ?? ""); } catch {}
});
}
// CRITICAL: wait for smartfield.js to load before creating element
if (customElements.get("smart-field")) createField();
else customElements.whenDefined("smart-field").then(createField);
return () => {
if (sfRef.current && container.contains(sfRef.current))
container.removeChild(sfRef.current);
if (id) _values.delete(id);
sfRef.current = null;
mountedRef.current = false;
};
}, []);
return <div ref={containerRef} />;
}
export const SmartField = memo(SmartFieldInner);
// Read plaintext value (3 fallback levels)
export function getSmartFieldValue(id) {
const el = document.getElementById(id);
try { const v = el?.getRealValue?.(); if (v !== undefined) return v; } catch {}
try { const v = el?._s?.("realValue"); if (v !== undefined) return v; } catch {}
return _values.get(id) || "";
}
// Read encrypted value (for server-side decryption)
export function getSmartFieldEncrypted(id) {
const el = document.getElementById(id);
return el?.value || "";
}
Step 3: Use in your login page
// app/login/page.tsx
"use client";
import { SmartField, getSmartFieldValue } from "@/components/SmartField";
export default function LoginPage() {
async function handleSubmit(e) {
e.preventDefault();
const email = getSmartFieldValue("sf-email");
const password = getSmartFieldValue("sf-pwd");
await fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ email, password })
});
}
return (
<form onSubmit={handleSubmit}>
<SmartField id="sf-email" type="email" placeholder="Email"
sfSecurity="peek" encryptKey="/sf-key" />
<SmartField id="sf-pwd" type="password" placeholder="Password"
sfSecurity="peek" encryptKey="/sf-key" />
<button type="submit">Log In</button>
</form>
);
}
customElements.whenDefined() to wait for the script, memo() to prevent re-renders, and mountedRef to handle React Strict Mode. Without this, SmartField loses all typed data on state changes.Vue.js
<!-- In your index.html -->
<script src="https://smartfield.dev/component/smartfield.js"></script>
<!-- In your Vue component -->
<template>
<form @submit.prevent="handleLogin">
<smart-field type="email" placeholder="Email"
encrypt-key="/api/sf-key" ref="email"></smart-field>
<smart-field type="password" placeholder="Password"
encrypt-key="/api/sf-key" ref="password"></smart-field>
<button type="submit">Log In</button>
</form>
</template>
<script>
// Tell Vue to ignore smart-field as a custom element
// In vite.config.js:
// vue({ template: { compilerOptions: { isCustomElement: tag => tag === 'smart-field' } } })
</script>
Angular
// In angular.json, add to scripts:
"scripts": ["https://smartfield.dev/component/smartfield.js"]
// In app.module.ts:
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@NgModule({
schemas: [CUSTOM_ELEMENTS_SCHEMA] // allows smart-field tag
})
// In your template:
<smart-field type="password" placeholder="Password"
encrypt-key="/api/sf-key"></smart-field>
Security Modes (sf-security)
SmartField has 3 display modes for how typed characters appear:
<!-- MAX (default): All characters are cipher symbols. Never reveals real text. -->
<smart-field sf-security="max"></smart-field>
<!-- User types "hello" → screen shows "ΣΩΔψξ" -->
<!-- PEEK: Hold the eye button to reveal text for 5 seconds -->
<smart-field sf-security="peek"></smart-field>
<!-- User holds 👁 button → shows "hello" for 5s with countdown bar -->
<!-- BRIEF: Shows each character for 1 second, then replaces with cipher -->
<smart-field sf-security="brief"></smart-field>
<!-- User types "h" → shows "h" for 1s → becomes "Σ" -->
peek for login forms (users can verify their input). Use max for payment fields (maximum security). Use brief for general forms.Stealth Mode (sf-stealth)
Hides the field's purpose from bots that read HTML source:
<!-- Without stealth: bots see placeholder="password" in HTML source -->
<smart-field type="password" placeholder="password"></smart-field>
<!-- With stealth: placeholder shows cipher chars, reveals real text on focus for 2s -->
<smart-field type="password" placeholder="password" sf-stealth></smart-field>
<!-- HTML source shows: placeholder="ΣΩΔψξ" -->
<!-- On focus: shows "password" for 2s, then fades to cipher -->
Field Types (sf-type)
<!-- Credit card: 16 digits only, blocks letters -->
<smart-field sf-type="card"></smart-field>
<!-- Expiry: MM/YY auto-format, validates month 01-12 -->
<smart-field sf-type="expiry"></smart-field>
<!-- CVV: 3-4 digits only -->
<smart-field sf-type="cvv"></smart-field>
<!-- SSN: 9 digits only -->
<smart-field sf-type="ssn"></smart-field>
<!-- Phone: 10-15 digits -->
<smart-field sf-type="phone"></smart-field>
<!-- Password: any text -->
<smart-field type="password"></smart-field>
<!-- Free text: no restrictions -->
<smart-field></smart-field>
Custom Styling
/* SmartField uses CSS Custom Properties */
smart-field {
--sf-bg: #ffffff; /* background */
--sf-border-color: #e5e7eb; /* border */
--sf-radius: 10px; /* border radius */
--sf-focus-color: #00B88A; /* focus border color */
--sf-focus-ring: rgba(0,184,138,0.12); /* focus glow */
--sf-cipher-color: #00B88A; /* encrypted character color */
--sf-cipher-glow: rgba(0,184,138,0.3); /* character glow */
--sf-placeholder-color: #bbb;
--sf-font-size: 14px;
--sf-padding: 12px 16px;
}
Security Architecture
ENCRYPTION: Hybrid AES-256-GCM + RSA-OAEP-2048
User types → AES key generated (random, per encryption)
→ Data encrypted with AES-256-GCM
→ AES key encrypted with server's RSA-2048 public key
→ Payload: base64(JSON{version, iv, encryptedKey, encryptedData})
→ Sent to server
→ Server decrypts AES key with RSA private key
→ Server decrypts data with AES key
→ Plaintext available ONLY on server
What SmartField blocks (20/20 verified)
1. .value → returns encrypted payload
2. .shadowRoot → returns null (closed)
3. .innerHTML → returns ""
4. .textContent → returns ""
5. .innerText → returns ""
6. querySelector("input") → returns null
7. querySelectorAll("*") → returns []
8. children / childNodes → empty
9. outerHTML → no plaintext value
10. .type / .name / .length→ hidden (encrypted / random / -1)
11. .value = "inject" → blocked
12. keydown event listener → events don't propagate
13. Prototype pollution → returns encrypted
14. MutationObserver → can't observe closed Shadow DOM
15. getComputedStyle → no data in CSS
16. Input overlay attack → keystrokes go to Shadow DOM
17. document.execCommand → blocked by Shadow DOM
18. JSON.stringify → sensitive data in WeakMap (invisible)
19. Property enumeration → no plaintext properties
20. Accessibility APIs → no data in ARIA
Troubleshooting by Stack
SmartField has been tested end-to-end with Node.js, Python, Java, Go, PHP, and Ruby. All SDKs decrypt correctly. Below are real issues we encountered during integration testing and how to fix them.
All Stacks. Field Limit (Free Plan)
The free plan allows 3 SmartFields per page. Fields beyond the limit are automatically blocked. Fix:
- Reduce to 3 SmartFields per page, OR
- Add your license key:
<script src="smartfield.js" data-key="sf_live_xxx"></script>
All Stacks. Peek Mode Text Invisible on Dark Backgrounds
SmartField auto-detects background brightness and adjusts the peek text color. If auto-detection fails (e.g., transparent backgrounds), set the color explicitly:
smart-field {
--sf-peek-color: #ffffff; /* white text for dark backgrounds */
}
All Stacks. Wrong Attribute Name
max mode regardless of setting.
The correct attribute is sf-security, not security:
<!-- ❌ Wrong -->
<smart-field security="peek" ...>
<!-- ✅ Correct -->
<smart-field sf-security="peek" ...>
PHP. JSON Response Contaminated with Print Output
Unexpected token 'S' or similar JSON parse error. The PHP server returns text before the JSON payload.
Any echo, print, or var_dump before your JSON response will break the output. This includes initialization messages from the SmartField SDK.
// ❌ This breaks JSON responses. output goes to browser
echo "[SmartField] Keys loaded";
// ✅ Use error_log instead. output goes to server logs only
error_log("[SmartField] Keys loaded");
php -S), anything printed outside a response handler also contaminates the output. Always use error_log() for debug messages.
Ruby (WEBrick). CORS Preflight Fails
Failed to fetch error when SmartField tries to get the public key or submit data cross-origin. Works with curl but fails in the browser.
WEBrick intercepts OPTIONS requests before they reach your route handler, so CORS headers are never sent. Use RequestCallback to inject CORS headers globally:
server = WEBrick::HTTPServer.new(
Port: 9999,
RequestCallback: proc { |req, res|
res['Access-Control-Allow-Origin'] = '*'
res['Access-Control-Allow-Headers'] = 'Content-Type'
res['Access-Control-Allow-Methods'] = 'GET, POST, OPTIONS'
}
)
rack-cors gem instead, which handles preflight correctly.
Java (HttpServer). Cross-Origin Blocked by Browser
Failed to fetch when SmartField component is served from a different origin than the Java server. CORS headers are present but browser still blocks.
Some browsers enforce stricter CORS rules for certain header combinations. The simplest fix is to proxy requests through your frontend server so everything is same-origin:
// Express proxy example (frontend server)
app.all('/proxy/java/:path', (req, res) => {
const http = require('http');
const options = {
hostname: 'localhost', port: 6666,
path: '/' + req.params.path,
method: req.method,
headers: { 'Content-Type': 'application/json' }
};
const proxy = http.request(options, (proxyRes) => {
let data = '';
proxyRes.on('data', c => data += c);
proxyRes.on('end', () => res.type('json').send(data));
});
if (req.body) proxy.write(JSON.stringify(req.body));
proxy.end();
});
// SmartField uses the proxy URL
<smart-field encrypt-key="/proxy/java/sf-key">
Go, Python, Node.js. No Issues
Mobile Devices. Standard Input Mode
Mobile browsers do not support browser extensions, which eliminates the primary attack vector SmartField protects against:
- Desktop: extensions, Hotjar, FullStory, injected scripts, XSS can all read
<input>values. SmartField encrypts them. - Mobile: no extensions, apps are sandboxed by the OS, third-party scripts have limited access. A standard input is already more secure than on desktop.
SmartField detects mobile devices automatically. No configuration needed. The <smart-field> tag still works. it just renders as a normal input on mobile and an encrypted field on desktop.
General. CORS Checklist
If you're getting Failed to fetch errors, verify your server returns these headers on both OPTIONS and regular responses:
Access-Control-Allow-Origin: *
Access-Control-Allow-Headers: Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS
Test with curl to confirm:
# Test preflight
curl -X OPTIONS http://localhost:PORT/sf-key \
-H "Origin: http://localhost:3000" \
-H "Access-Control-Request-Method: GET" \
-H "Access-Control-Request-Headers: Content-Type" -D -
# You should see all 3 Access-Control headers in the response
What SmartField Protects. And What It Doesn't
We believe in transparency. No security product is 100%. Here's exactly what SmartField covers and what it doesn't.
SmartField PROTECTS against:
| Attack | How |
|---|---|
| JavaScript reading .value | Returns encrypted payload only |
| Trackers (Hotjar, GA, FullStory) | Shadow DOM + event blocking |
| XSS attacks | Attacker gets encrypted gibberish |
| Screen recorders | Cipher characters + scramble on blur |
| Bots and AI agents | Shadow DOM blocks querySelector |
| Copy / paste / select | All clipboard events blocked |
| Prototype pollution | value property is non-configurable |
| JSON serialization | Sensitive data in WeakMap (invisible) |
| MutationObserver | Cannot observe closed Shadow DOM |
| Browser autofill / autosave | Input shows cipher chars, not real data |
SmartField DOES NOT protect against:
| Attack | Why |
|---|---|
| Malicious browser extensions | Extensions with elevated permissions operate below the JavaScript layer. SmartField cannot block them. This is a browser-level limitation, not a SmartField limitation. |
| OS-level keyloggers | A keylogger installed on the operating system captures keystrokes before they reach the browser. No web technology can prevent this. |
| Physical access to the machine | Someone with physical access can install keyloggers, use hardware devices, or read the screen directly. This requires endpoint security, not web security. |
| Browser zero-day exploits | A vulnerability in Chrome/Firefox itself could bypass Shadow DOM. If this happens, the entire browser is compromised. not just SmartField. |
| RAM dump with root access | With root/admin access to the machine, an attacker could read browser process memory. This requires full system compromise. |
API Reference. SDK Methods
Server SDK (Node.js)
const sf = require('@smartfield-dev/server');
await sf.init() // Generate or load RSA keys
sf.getPublicKey() // Returns JWK public key
await sf.decrypt(payload) // Decrypt a single field
await sf.decryptFields(body) // Decrypt all fields in an object
sf.middleware() // Express middleware (auto key + decrypt)
await sf.rotateKeys() // Rotate RSA keys (archives old ones)
sf.status() // Returns SDK state info
Client-side (Browser). v2.7+
const el = document.getElementById('sf-email');
el.value // Returns ENCRYPTED payload (for server decryption)
el.getRealValue() // Returns PLAINTEXT value (for client-side use)
el.hasValue() // Returns true/false (without revealing length)
el.clear() // Clears the field programmatically
// All methods above are non-enumerable and non-configurable:
// - Invisible to JSON.stringify, Object.keys, for..in
// - Cannot be overridden by attackers
.value → Send to your server for decryption (end-to-end encrypted flow).getRealValue() → Use client-side when you need plaintext (e.g. validation, sending to your own API)Use
.getRealValue() for React/Vue/Angular apps that handle form submission in JavaScript.Events
// sf-input: fires on every keystroke
document.querySelector('smart-field').addEventListener('sf-input', (e) => {
console.log(e.detail.id); // random field ID (sf_a7f3c2)
console.log(e.detail.encrypted); // encrypted payload
// NOTE: no plaintext, no field name, no length exposed
});
// sf-scan: fires after environment scan (500ms after mount)
el.addEventListener('sf-scan', (e) => {
console.log(e.detail.threats); // array of detected threats
console.log(e.detail.safe); // true if no threats found
});
// sf-threat: fires if phishing detected on form submit
el.addEventListener('sf-threat', (e) => {
console.log(e.detail.threats); // what was detected
console.log(e.detail.action); // 'fake_data_sent'
});
Compliance
SmartField's encryption architecture can help satisfy specific requirements in PCI-DSS, HIPAA, GDPR, and SOX. Below is an honest breakdown: what SmartField covers, and what you still need to handle yourself.
PCI-DSS
The Payment Card Industry Data Security Standard applies to any organization that stores, processes, or transmits cardholder data. SmartField directly addresses three requirements:
| Requirement | What it says | How SmartField helps |
|---|---|---|
| 3.4. Render PAN unreadable anywhere it is stored | PAN must be protected using encryption, truncation, hashing, or tokenization | SmartField encrypts PAN at the moment of keystroke using AES-256-GCM. The value never exists as plaintext in the DOM, JavaScript memory, or network payload. With sf-type="card", input is validated to 16 digits before encryption. The browser never holds the raw PAN in a readable form. |
| 4.1. Encrypt cardholder data in transit over open networks | Use strong cryptography when transmitting cardholder data | Data is encrypted client-side with AES-256-GCM before form submission. The AES key itself is wrapped with RSA-OAEP-2048. This means cardholder data is encrypted before it hits TLS. providing a second encryption layer. Even if TLS is compromised (MITM, misconfigured proxy), the payload remains encrypted. |
| 6.5. Address common coding vulnerabilities | Protect against XSS, injection, and other OWASP Top 10 issues in web applications | SmartField's closed Shadow DOM prevents XSS attacks from reading field values. Even if an attacker injects a script, .value returns an encrypted payload, .shadowRoot returns null, and no DOM traversal method exposes plaintext. Clipboard events (copy/paste/select) are blocked. |
What you still need to do:
- Your server must decrypt and process card data in a PCI-compliant environment (SAQ A, SAQ A-EP, or SAQ D depending on your integration model)
- Store decrypted PAN according to Requirement 3. never log it, never write it to disk unencrypted
- Implement access controls (Req 7, 8), network segmentation (Req 1), monitoring (Req 10, 11)
- SmartField reduces your client-side attack surface but does not eliminate the need for a QSA assessment if you handle card data server-side
- If you use SmartField to send encrypted card data to a PCI-compliant payment processor that handles decryption, you may qualify for SAQ A-EP (reduced scope)
HIPAA
The Health Insurance Portability and Accountability Act requires protection of PHI (Protected Health Information). names, dates, SSNs, medical record numbers, and any data that can identify a patient.
| Safeguard | HIPAA requirement | How SmartField helps |
|---|---|---|
| Technical Safeguard §164.312(a)(1). Access Control | Implement technical policies to allow access only to authorized persons | PHI entered in SmartField is immediately encrypted. JavaScript on the page (including third-party scripts, analytics, and injected code) cannot read the plaintext. Only your server with the RSA private key can decrypt. This limits access to PHI at the point of capture. |
| Technical Safeguard §164.312(e)(1). Transmission Security | Protect PHI during electronic transmission | PHI is encrypted with AES-256-GCM + RSA-2048 before transmission. This operates independently of (and in addition to) TLS. PHI is encrypted in the browser and decrypted only on your server. |
| Technical Safeguard §164.312(a)(2)(iv). Encryption and Decryption | Encrypt ePHI as appropriate | SmartField encrypts all field data using NIST-recommended algorithms (AES-256-GCM, RSA-OAEP). Encryption happens automatically. developers cannot accidentally skip it. |
What you still need to do:
- Sign a BAA (Business Associate Agreement) with any third party that handles PHI. SmartField never receives or stores PHI (encryption/decryption happens entirely on your infrastructure), so a BAA with SmartField is not required
- Implement server-side access controls, audit logging, and breach notification procedures
- Ensure your server environment meets HIPAA physical and administrative safeguards
- Conduct a risk assessment covering your full stack, not just the client-side layer
- Train staff on PHI handling procedures. SmartField protects data in the browser, not after decryption
GDPR
The General Data Protection Regulation requires protection of personal data for EU residents. SmartField addresses several GDPR principles at the data capture layer.
| Principle | GDPR article | How SmartField helps |
|---|---|---|
| Data Minimization | Article 5(1)(c) | SmartField's random field IDs (sf_a7f3c2) mean that even the encrypted payload does not reveal what type of data was collected. There are no field names like "email" or "password" in the submitted form data. Third-party scripts on the page cannot determine what data the form collects. |
| Integrity & Confidentiality | Article 5(1)(f) | Personal data is encrypted at the earliest possible point. the moment of keystroke. AES-256-GCM provides both confidentiality (encryption) and integrity (authentication tag). Data cannot be tampered with or read between capture and server-side decryption. |
| Data Protection by Design | Article 25 | SmartField enforces encryption by default. There is no "unencrypted mode." Developers cannot accidentally expose personal data because .value always returns the encrypted payload. This is protection by design, not by policy. |
| Security of Processing | Article 32 | SmartField implements encryption, pseudonymization (random field IDs), and protection against unauthorized disclosure (closed Shadow DOM blocks third-party scripts). These are specific measures listed in Article 32(1)(a). |
What you still need to do:
- Implement lawful basis for processing (consent, legitimate interest, etc.). SmartField encrypts data, it does not manage consent
- Provide data subject rights: access, rectification, erasure, portability. these require server-side implementation
- Maintain a Record of Processing Activities (ROPA)
- Appoint a DPO if required, conduct DPIAs for high-risk processing
- Implement server-side data retention policies. SmartField protects data in transit, not at rest on your servers
- Ensure any analytics or third-party scripts comply with GDPR independently
SOX (Sarbanes-Oxley)
SOX Section 404 requires internal controls over financial reporting. For web applications that handle financial data (accounting portals, expense systems, internal financial tools), SmartField provides controls at the input layer.
| Control area | SOX requirement | How SmartField helps |
|---|---|---|
| IT General Controls. Data Integrity | Ensure accuracy and completeness of financial data | AES-256-GCM includes an authentication tag that detects any modification to the encrypted data. If a script or middlebox alters the payload in transit, decryption fails. This guarantees that financial data received by the server is exactly what the user entered. |
| IT General Controls. Access to Data | Restrict access to financial data to authorized personnel and systems | Financial figures entered in SmartField cannot be read by client-side JavaScript, browser extensions at the JS layer, or third-party scripts. Only your server with the private key can decrypt. This restricts access at the point of entry. |
| IT General Controls. Change Management | Ensure changes to applications do not compromise data integrity | SmartField's encryption is automatic and non-bypassable. A developer adding new frontend code cannot accidentally expose financial data. the architecture enforces protection regardless of application changes. |
What you still need to do:
- Implement server-side access controls, segregation of duties, and audit trails for financial data
- Maintain change management procedures for your full application stack
- Conduct regular SOX audits covering both IT general controls and application controls
- Ensure database-level encryption and access controls for stored financial data
- SmartField protects data during entry and transit. your server-side controls must protect it after decryption
License Keys
<!-- Free plan: no key needed -->
<script src="https://smartfield.dev/component/smartfield.js"></script>
<!-- Limit: 3 fields per page, badge shown -->
<!-- Paid plan: add your key -->
<script src="https://smartfield.dev/component/smartfield.js"
data-key="sf_live_your_key_here"></script>
<!-- Unlimited fields, no badge -->
Frequently Asked Questions
Why doesn't browser autofill work with SmartField?
This is intentional, not a bug.
Browser autofill is a security risk. When Chrome, Firefox, or Safari autofill your login form, the password is stored in the browser and inserted as plaintext into the DOM. This means:
- Anyone with access to your computer can open Chrome and the autofill gives them your password. no authentication required
- Any JavaScript on the page can read the autofilled value instantly
- Trackers and extensions can capture autofilled data before you even click "Log In"
- Shared/public computers may have previous users' credentials stored
SmartField blocks autofill by design: the input lives inside a closed Shadow DOM with autocomplete="off", password manager ignore flags, and type="text" (not "password"). The browser cannot detect, fill, or save the field.
sf-security="peek" so they can hold the eye icon to verify what they typed. this replaces the convenience of autofill with a secure alternative.Can I use SmartField alongside normal inputs?
Yes. You don't have to encrypt every field. Use SmartField for sensitive fields (passwords, card numbers, SSN) and normal <input> for non-sensitive fields (username, search, preferences). SmartField will even warn you if it detects unprotected <input type="password"> fields on the same page.
Does SmartField work on mobile?
Yes. SmartField supports both physical keyboards (keydown) and virtual keyboards (beforeinput) on iOS and Android. The cipher animation, peek mode, and encryption all work on mobile browsers.
What happens if the SmartField server goes down?
If you're using the free plan (no data-key), SmartField works 100% offline. it generates encryption keys locally in the browser. No server call needed.
If you're using a paid plan, SmartField caches the license in sessionStorage for 24 hours. If the license server is unreachable, it falls back gracefully to the free plan (3 fields, badge shown). Your forms never break.
Can attackers decrypt the data if they steal my public key?
No. The public key is public by design. it's served to every browser that loads your page. It can only encrypt, never decrypt. Only your server's private key (stored in .smartfield/) can decrypt. This is standard RSA asymmetric cryptography.
Is my API key (data-key) safe in my HTML?
Yes. Your API key is designed to be public, just like a Google Maps key or Stripe publishable key. It goes directly in your HTML:
<script src="smartfield.js" data-key="sf_live_xxx"></script>
You do NOT need to put it in a .env file or hide it. Here's why it's safe:
- Domain-locked: Your key is tied to your domain. If someone copies it and uses it on
hacker.com, the server rejects it and falls back to the free plan. It only works on the domain you registered. - No sensitive access: The key only tells SmartField "this site has a Pro plan." It doesn't grant access to any data, keys, or user information.
- Cannot decrypt data: Decryption requires your server's RSA private key (stored in
.smartfield/private.json). The API key has nothing to do with encryption or decryption.
- Your RSA private key (
.smartfield/private.json) — this decrypts user data - Your
DATABASE_URL, database passwords, or server credentials - Your
.licenses/directory
.gitignore by the SDK. Never commit them.data-key = public (like Google Maps key). .smartfield/private.json = secret (like your database password). Never mix them up.Why do field names show as random IDs (sf_a7f3c2)?
To prevent attackers from identifying which field contains the password. If the field name was "password", an attacker could target that specific field. Random IDs make all SmartField fields look identical. an attacker cannot distinguish the email from the password from the SSN.
Does SmartField slow down my page?
The SmartField script is ~15KB. Encryption uses the browser's native Web Crypto API (hardware-accelerated on most devices). Each keystroke encryption takes <1ms. There is no noticeable performance impact.