NIP-46 nostrconnect:// URL Parameter Format
SkillMediaFix NIP-46 nostrconnect:// URLs not being recognized by signer apps (Amber, nsec.app, nsecBunker). Use when: (1) QR code or URL paste fails in signer app despite valid-looking URL, (2) Using metadata JSON object instead of separate query params, (3) Implementing client-initiated NIP-46 connections. The NIP-46 spec requires name/url/image as separate query parameters, not a metadata JSON object.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use the NIP-46 nostrconnect:// URL Parameter Format skill
What this skill tells your AI
The instructions your AI receives, as published by divinevideo/divine-mobile in .agents/skills/nip46-nostrconnect-url-params/SKILL.md and read by ahel’s review.
Problem
When implementing NIP-46 client-initiated connections (nostrconnect://), signer apps may fail to recognize the URL if app metadata is passed as a JSON object instead of separate query parameters.
Context / Trigger Conditions
- Signer app (Amber, nsec.app, nsecBunker) shows error or fails silently when scanning/pasting URL
- URL contains
metadata={"name":"...","url":"..."}format - QR code generates successfully but signer doesn't connect
- Other parameters (relay, secret, perms) appear correct
Solution
Wrong (metadata JSON object):
nostrconnect://<pubkey>?relay=wss://relay.example.com&secret=abc123&metadata={"name":"MyApp","url":"https://myapp.com","icon":"https://myapp.com/icon.png"}&perms=sign_event
Correct (separate parameters per NIP-46):
nostrconnect://<pubkey>?relay=wss://relay.example.com&secret=abc123&name=MyApp&url=https://myapp.com&image=https://myapp.com/icon.png&perms=sign_event
Code fix example (Dart):
// WRONG - Don't bundle in metadata JSON
if (metadata.isNotEmpty) {
final metadataJson = jsonEncode(metadata);
params.add('metadata=${Uri.encodeComponent(metadataJson)}');
}
// CORRECT - Use separate params as specified in NIP-46
if (appName != null && appName.isNotEmpty) {
params.add('name=${Uri.encodeComponent(appName)}');
}
if (appUrl != null && appUrl.isNotEmpty) {
params.add('url=${Uri.encodeComponent(appUrl)}');
}
if (appIcon != null && appIcon.isNotEmpty) {
params.add('image=${Uri.encodeComponent(appIcon)}');
}
Verification
- Generate a nostrconnect:// URL
- Verify URL contains
name=,url=,image=as separate params (notmetadata=) - Test with signer app (Amber Android, nsec.app web, or nsecBunker)
- Signer should show app name and prompt for approval
NIP-46 Spec Reference
From NIP-46:
Additional information should be passed as query parameters:
name(optional) - the name of the client applicationurl(optional) - the canonical url of the client applicationimage(optional) - a small image representing the client application
The spec does NOT mention a metadata parameter - each field is a separate query param.
Notes
- All query parameter values should be URL-encoded
- The
relayparameter can appear multiple times for multiple relays - The
secretparameter is REQUIRED for nostrconnect:// (not optional like bunker://) - Some signer apps may be more lenient than others - always follow spec exactly
- Note the param is
image, noticon(easy to confuse with the metadata field name)
References
Signals
- GitHub stars
- 264
- Forks
- 55
- Last commit
- Sep 2026
Advanced
- Catalog kind
- skill
- Gateway key
nip46-nostrconnect-url-params- Source
- github.com/divinevideo/divine-mobile