Lens studio networking
Use when a Lens / Spectacles lens talks to an external backend via InternetModule.fetch — the Preview is device-only and throws synchronously, `Request` isn't a runtime constructor, and microphone + network APIs are mutually exclusive. Includes the companion-app pattern for voice without an on-device mic.From its SKILL.md
npx -y skills add zajalist/zajal-skills --skill lens-studio-networkingAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
4.1 KB, 954 tokens by cl100k_base, as published. Nobody here has run it
Networking from a Lens (InternetModule.fetch)
Calling an HTTP backend from a Spectacles lens. The API is small but every step has a non-obvious trap, and two whole capabilities (mic + network) can't coexist.
fetch is DEVICE-ONLY — the desktop Preview throws unless you force Spectacles
InternetModule.fetch does not run in the desktop Preview by default. It throws:
InternalError: Cannot invoke 'fetch': API not available on the simulated platform
The fix is in the Preview panel: set Device Type Override → Spectacles. With any other device type (or none) the simulated platform has no networking and every fetch dies. Tell the user to set this; you can't toggle it over MCP.
The fetch call throws SYNCHRONOUSLY — wrap it in try/catch, not .catch
In the Preview the error above is thrown synchronously from the fetch(...) call itself, before
any promise exists. A .catch() on the returned promise will not catch it. Always guard the call:
try {
const resp = await this.internetModule.fetch(url, { method: "GET" });
const data = await resp.json();
} catch (e) {
print("fetch failed: " + e); // catches the synchronous "not available" throw too
}
Request is NOT a runtime constructor — pass a URL string
Request appears as a type in the .d.ts, so it's tempting to write
internetModule.fetch(new Request(url)). At runtime that throws:
ReferenceError: 'Request' is not defined
There is no Request constructor in LS scripting. Pass the URL as a plain string and put method /
headers / body in the options object:
internetModule.fetch(url, { method: "GET" });
internetModule.fetch(url, { method: "POST", body: JSON.stringify(payload) });
Get the InternetModule via an @input internetModule: InternetModule (wire the asset) or
require("InternetModule").
⚠️ Microphone and network are MUTUALLY EXCLUSIVE
A lens that opens the microphone (sensitive user data) cannot also use InternetModule to
reach an external backend. Combining them fails with:
Sensitive user data not available in lenses with network APIs
This is a platform privacy rule, not a bug. The mic is "sensitive data"; an arbitrary external network endpoint could exfiltrate it, so Snap forbids both in the same lens. Only Remote Service Gateway / Snap Cloud are exempt — those are the sanctioned way to combine mic + cloud.
The companion-app pattern (voice without an on-device mic)
When you can't use Remote Service Gateway and still want voice, move the mic off the lens:
- A companion app (phone or laptop) is the microphone. It captures speech, does STT, and POSTs the text to your backend.
- The lens has no mic — so it's free to use
InternetModule. It polls the backend for the latest text/answer and renders it.
The lens never touches sensitive data, so the network restriction doesn't apply. This is the practical way to ship a "talk to it" Spectacles experience against your own backend without RSG.
Checklist
@input internetModule: InternetModule(orrequire).- Preview panel → Device Type Override = Spectacles (or fetch is unavailable).
fetch(urlString, { method, body })— nevernew Request(...).- Wrap the call in try/catch (it throws synchronously in Preview).
- If you need the mic AND a backend: use Remote Service Gateway, or split into a companion app (mic + POST) and a poll-only lens.
- Verify visually — runtime
printlogs are often unreadable (preview-verify).
Related: preview-verify (Device Type Override lives in the
same Preview panel; reading logs), mcp-editing (wiring the
InternetModule @input).
What ships with it
Read from the repository
Just SKILL.md. No reference files, no scripts.