I have a simple opinion about product feedback: if you ask at the wrong time, you get worse answers.
The research bears this out, feedback collected at the moment of friction beats the same question asked days later, and timing often moves response quality more than copy does. That is why we built in-product targeting for Formaly.
The hard part was not rendering a popup. That part is easy. The harder part was building an SDK that is small, predictable, respectful, and genuinely useful for real product teams.
The constraints
Before writing a line of the SDK, I wrote down the constraints:
| Constraint | Why it mattered |
|---|---|
| Small runtime | Nobody wants a survey SDK that slows their app |
| Simple install | One script tag, not a project |
| Clear triggers | Teams should understand why a survey appeared |
| Cooldowns | Users should not be chased around the product |
| Manual escape hatch | Teams need full control for important moments |
These constraints forced the product to stay focused, which, with feedback tooling, is most of the battle.
Why triggers are intentionally boring
It is tempting to build a huge targeting engine. The problem is that huge targeting engines become impossible to reason about, and a rule nobody understands is a rule nobody trusts.
We shipped the triggers teams actually need:
- Page view
- Delay
- Scroll depth
- Exit intent
- Element click
- Manual call (
Formaly.show())
…plus targeting conditions that match on URL and user attributes, so a trigger only fires for the right segment. A product manager can understand "show after the user clicks this button, but only for trial accounts" without reading documentation for an hour. Boring primitives are predictable primitives.
Display modes are different social contracts
The SDK supports popup, slide-in, and widget, and each one is a different agreement with the user:
| Display | Use it when | Avoid it when |
|---|---|---|
| Popup | The feedback moment is important | The user is mid-flow in something delicate |
| Slide-in | You want visibility with less interruption | The question is long or sensitive |
| Widget | Feedback should be user-initiated | You need a high response rate immediately |
"Show a survey" is not one UX pattern, so the SDK does not pretend it is.
Cooldowns are product quality, not a setting
Cooldowns are not a nice-to-have. They are how the SDK respects the user.
If someone dismisses a survey, the SDK remembers. If someone completes one, it stops asking. If a team runs several surveys at once, the product should still feel calm rather than like a popup carousel. This is one of those details users only notice when it is wrong, which is exactly why it has to be right by default.
Why small matters
An SDK that runs on a customer's site has to earn its place. The runtime's whole job is to fetch config, evaluate triggers and conditions, render the chosen display mode in an isolated iframe, send events, and otherwise stay quiet.
No giant framework assumptions. No unnecessary dependencies. No surprise behavior. The survey loads in an iframe so it cannot interfere with the host page's styles or scripts, the host app stays exactly as fast and as stable as it was.
What I am optimizing for
In-product surveys are not about asking more questions. They are about asking fewer, better-timed ones.
The best implementation disappears when it should disappear and shows up only when the user's context makes the question worth asking. That is the bar for the Formaly SDK, and it is the same philosophy behind the public SDK announcement and the broader idea that static forms are overused, not dead.