Without code signing, users will see security warnings:
- Windows: "Windows protected your PC" (SmartScreen)
- macOS: "Cannot be opened because it is from an unidentified developer" (Gatekeeper)
Code signing proves your app is legitimate and hasn't been tampered with.
Timeline: 2-4 weeks Cost: $0
How it works:
- Windows SmartScreen builds reputation based on downloads
- After ~100-500 downloads, warnings disappear automatically
- No certificate needed
Pros:
- ✅ Free
- ✅ No setup required
Cons:
⚠️ Users see warnings initially⚠️ Takes time to build reputation⚠️ Reputation resets with each new version
Recommended for: Initial launch, testing market fit
Timeline: 1-3 days Cost: $199-474/year
Providers:
- SSL.com - $199/year (cheapest)
- Sectigo (Comodo) - $199/year
- DigiCert - $474/year (most trusted)
What you get:
- ✅ Sign Windows .exe files
- ✅ Sign macOS .app files
- ✅ Reduces (but doesn't eliminate) SmartScreen warnings
- ✅ Still need to build reputation
Setup time: 1-3 business days (identity verification)
Recommended for: Established apps, professional image
Timeline: 3-7 days Cost: $299-599/year
Providers:
- SSL.com - $299/year
- DigiCert - $599/year
What you get:
- ✅ Instant SmartScreen trust (no reputation needed!)
- ✅ No warnings from day 1
- ✅ Hardware token (USB key) for security
- ✅ Higher trust level
Setup time: 3-7 business days (stricter identity verification)
Recommended for: Professional launch, enterprise customers
Recommended: SSL.com (best price/value)
- Standard: $199/year
- EV: $299/year
- Link: https://www.ssl.com/code-signing/
You'll need:
- Business registration documents (or personal ID)
- Phone number verification
- Email verification
- DUNS number (for EV only)
Timeline:
- Standard: 1-3 days
- EV: 3-7 days
- Standard: Download .pfx file
- EV: Receive USB hardware token in mail
For Windows (Standard Certificate):
// package.json
{
"build": {
"win": {
"certificateFile": "./certificates/fileshot-cert.pfx",
"certificatePassword": "YOUR_PASSWORD_HERE",
"signingHashAlgorithms": ["sha256"],
"sign": "./sign.js"
}
}
}For Windows (EV Certificate with USB token):
{
"build": {
"win": {
"sign": "./sign-ev.js",
"signingHashAlgorithms": ["sha256"]
}
}
}For macOS:
{
"build": {
"mac": {
"identity": "Developer ID Application: Your Name (TEAM_ID)",
"hardenedRuntime": true,
"gatekeeperAssess": false,
"entitlements": "build/entitlements.mac.plist",
"entitlementsInherit": "build/entitlements.mac.plist"
}
}
}| Option | Year 1 | Year 2+ | SmartScreen | Setup Time |
|---|---|---|---|---|
| No Certificate | $0 | $0 | 0 days | |
| Standard Cert | $199-474 | $199-474 | 1-3 days | |
| EV Certificate | $299-599 | $299-599 | ✅ No warnings (instant) | 3-7 days |
Use: No certificate (free)
- Launch app unsigned
- Users click "More info" → "Run anyway"
- Build initial user base
- Collect feedback
Cost: $0
Use: Standard certificate ($199/year)
- Purchase SSL.com standard cert
- Sign all releases
- Professional appearance
- Reduced warnings
Cost: $199/year
Use: EV certificate ($299/year)
- Upgrade to EV cert
- Zero warnings
- Enterprise-ready
- Maximum trust
Cost: $299/year
-
Purchase certificate from SSL.com
-
Download .pfx file after verification
-
Store securely:
mkdir certificates mv fileshot-cert.pfx certificates/ # Add certificates/ to .gitignore -
Create sign.js:
const { execSync } = require('child_process'); exports.default = async function(configuration) { const certPath = './certificates/fileshot-cert.pfx'; const certPassword = process.env.CERT_PASSWORD; execSync(`signtool sign /f "${certPath}" /p "${certPassword}" /tr http://timestamp.digicert.com /td sha256 /fd sha256 "${configuration.path}"`); };
-
Set environment variable:
# Windows set CERT_PASSWORD=your_password_here # Mac/Linux export CERT_PASSWORD=your_password_here
-
Build signed app:
npm run build:win
-
Join Apple Developer Program ($99/year)
-
Create Developer ID Certificate:
- Xcode → Preferences → Accounts
- Manage Certificates → + → Developer ID Application
-
Get Team ID:
security find-identity -v -p codesigning
-
Update package.json:
{ "build": { "mac": { "identity": "Developer ID Application: Your Name (TEAM_ID)" } } } -
Build signed app:
npm run build:mac
- ✅ Never commit certificates to Git
- ✅ Add to .gitignore
- ✅ Use environment variables for passwords
- ✅ Store backups securely (encrypted)
- ✅ Revoke if compromised
# .env (add to .gitignore!)
CERT_PASSWORD=your_secure_password
APPLE_ID=your@email.com
APPLE_ID_PASSWORD=app-specific-passwordCertificate Issues:
- SSL.com Support: https://www.ssl.com/support/
- DigiCert Support: https://www.digicert.com/support/
Electron Builder:
- Docs: https://www.electron.build/code-signing
- GitHub: https://github.com/electron-userland/electron-builder
After signing, verify your certificate:
Windows:
signtool verify /pa /v FileShot-Setup-1.0.0.exemacOS:
codesign --verify --deep --strict --verbose=2 FileShot.app
spctl -a -t exec -vv FileShot.appFor immediate launch: Start unsigned, accept warnings For professional image: Get standard cert ($199/year) For zero warnings: Get EV cert ($299/year)
My recommendation: Launch unsigned first, upgrade to EV cert after validating market fit.