QueryInterface: A query-based API for Framer prototypes

A handy module that allows end users to customize their viewing experience of your Framer prototype.

Marc Krenn
Framer
8 min readMar 27, 2017

--

APIs, Application Programming Interfaces, regulate access to data and allow code, websites and apps to interact with each other. Prototypes can certainly benefit from having their own APIs, as I will demonstrate below. In order to establish an API, we are going to use a module called QueryInterface. This module allows Framer prototypes to read variables from and write variables to the last part of the URL, the query:

This example is available here.

In order to create such a variable that shows up in the query, a new QueryInterface-object must be initiated with two required properties: key and default. This works similar to how you’d define a new Layer in Framer. The value of the variable can then be accessed and modified using its value-property:

As you can see in the animation above, you can change bgColor in two different ways: Either by overwriting its value in the address bar or by clicking on the Canvas, which will programmatically overwrite bgColor with a new, random color. Thanks to some HTML5 magic, the latter will also update bgColor in the address bar.

When copy-pasting this newly modified Framer Cloud URL into another tab, window or browser, the color defined in bgColor will be injected into the prototype. This link here https://framer.cloud/ebcEA/?bgColor=red, for instance, will inject red as a color.

Pretty cool, huh? Oh, and did I mention that your can have as many variables as you want?

“I’ve seen or used similar techniques before. What’s all the fuss about?”

Dealing with the query in a consistent, controlled and secure manner turned out to be surprisingly tricky. So, I thought it would be nice to have a module that would deal with all of these annoyances for us.

The module would have to meet the following three requirements:

  1. Easy setup and use:
    As seen in the example above, QueryInterface only requires a minimal setup of only 3–5 lines of code, with the module doing all the heavy lifting for you in the background.
  2. Broad data type support and safe type conversion:
    QueryInterface supports all common data types: Booleans, numbers, strings, generic objects including arrays and yes, even JSON-encoded data. A lot could be said about how it handles type conversion and how it prevents people from breaking your prototype by entering invalid inputs. Anyway, all you have to know is: It’s safe, secure and just works as you’d expect it to.
  3. Data persistence:
    Previously set query-data is usually lost after a site refresh or an update to your prototype. QueryInterface, however, saves and loads previously set data automatically. If you don’t want or need this for whatever reason, you can fully customise its data persistence behaviour by a number of optional properties, which can be found in the module’s documentation on github.*

The module’s github repo is also where you can find more information, examples and a Getting started-guide.

* PROTIP: QueryInterface can also be used to simply save and load values across multiple sessions without touching any of the query-aspects of the module. In this case, just set the publish- and fetchQuery-properties to false.

Four everyday use cases for QueryInterface

At this point you may wonder how you and your prototype are supposed to benefit from all of this. I asked this to myself and came up with the following four use cases, which will hopefully inspire you to come up with your own ideas and ways of utilizing QueryInterface in your workflow.

If you do, I’d really appreciate if you’d share them with all of us in the comments below. Thanks!

1) Give others easy and controlled editing capabilities

As a reader of this article, chances are you’re into prototyping and, to some extent, programming. But needless to say, not all people are; people like your non-coding colleagues and clients.

In my experience, there are sometimes situations where you’d wish to give those people the ability to change some particular parameters or aspects of your prototype — without having them to learn how to code first.

This is especially true when working remotely with someone on cosmetic adjustments of your prototype, like the appearance of graphical elements (e.g. backgroundColors, borderRadii), animation parameters, text-labels and so on.

Let’s use the code snippet from above as a simple example. As a reminder, this one allows the prototype’s backgroundColor to be set via the browser’s address bar, using a QueryInterface-variable called bgColor. Here’s what you’d do:

  1. Upload the prototype to Framer Cloud.
  2. If you want to, you can open up the share link and alter the value of bgColor, either directly via the address bar or by clicking somewhere on the canvas of the prototype. If you don’t do that (or share the unmodified vanilla link without the query), the color set as bgColor.default will be used instead.
  3. Finally, share the (un)modified Framer Cloud link with others and tell them how they can modify the available variable(s). Something along the lines of:

2) Multiple design variations

With QueryInterface it’s super simple to prepare multiple design variations of the same prototype for upcoming design reviews.

Now, instead of saving every design variation as separate Framer file, as you’d normally do, incorporate QueryInterface-variables into your prototype and upload it to Framer Cloud.

Open the Framer Cloud link in your browser and change all the variables which make up a design variation. A variation can be made up of as many variables as needed— e.g. one for the primary color, one for animation-values, and so on.*

Whenever you’re happy with a variation, simply save the link, either in the description of your prototype, in a note keeping app of your choice or directly as a bookmark in your browser. During design review, just open the respective links to load a design variation.

In the context of our simple backgroundColor-example, a collection of design variations would look something like this:

What’s really cool about this approach is that you only have to maintain one source code. So, if you fix a bug or add new features later on, just upload the new iteration of your project to Framer Cloud and all of the previously defined variation should still work.

* Or you can only use a single variable, loading a JSON-encoded “design sheet”.

3) Programatic mass-customization

This one is a natural extension of the idea above: As prototype variations are only modified share links, it’s pretty obvious that you can use programs, scripts and services to create those links programmatically. This concept can, for instance, be used to mass-customize prototypes for individual testers — think personal profile data, different versions for A/B testing, and so on.

Take this prototype as an example: It allows for a Twitter handle to be set via QueryInterface, which is used to display the corresponding profile image from Twitter. Such details not only put a smile on E̶l̶o̶n̶’s your tester’s face but also increases the believability of your prototype.

Open this exact state (handle + sliders) with this link *

The easiest way to create those links programmatically is probably with Google docs tables. Here’s what a Google Docs setup could look like:

Google Docs spreadsheet (read only)

However, what’s way cooler is to use a service like MailChimp, which allows you to embed your subscriber’s personal data in mail campaigns. In the following basic step-by-step guide (which is, by the way, based on this tutorial), I’m going to explain how you could add personalized prototypes to your mail campaigns, using the Twitter example from above:

  1. Ask subscribers for required data:
    Create a new form element for Twitter handle. Set an appropriate field tag.
  2. Verify:
    Navigate to Lists*YourListName*Settings → List fields and *|MERGE|* tags. Check if the field created in step #1 shows up in this list.
  3. Create a new Template:
    In order to use the subscriber’s personal data, use field tags (*|HANDLE|*, *|NAME|*, etc.). Important: The preview and test mails won’t fill in any dynamic data for those field tags.
  4. Result:
    A personalized mail including a programmatically created link to a personalized prototype.

* PROTIP: If you don’t want lots of QueryInterface-variables to show up in the address bar, simply set their publish-property to false. The query will be removed the very second the link is opened.

4) Supercharged Flow Component

Incorporating QueryInterface into Flow Component-based prototypes, like in this one here, has two major benefits:

https://framer.cloud/AbGDe/
  1. It allows to link directly to specific views, like seen in the image above: (https://framer.cloud/AbGDe/?screen=photo). The share link is automatically being updated when switching between views.
  2. Let’s say, you’re working on a view that’s pretty low in the navigational hierarchy of your prototype, meaning, it requires some clicks or taps to get there. What you’d usually do is to write some code, stop and wait for Framer to reload your prototype — this will inevitably take you back to the initial view of your prototype. So, what you’d do next is to navigate to the view you’re currently working on, in order to see the effect of the newly written code.
    Doing this tens- or hundreds of times during development is not only a huge waste of time but also pretty annoying. QueryInterface gets rid of this redundant step, by automatically reloading the view you’re currently working on. To see this in action, download and open the example above in Framer.

Thanks for making it all the way down here! As always, I’d really appreciate your feedback on both the article and module. Also, please don’t hesitate to get in touch if you need some assistance or have any question— I’m always happy to help.

You can reach me via Twitter, Facebook or Slack.

Thanks to Benjamin den Boer for allowing me to remix his prototypes.

--

--

Marc Krenn
Framer
Writer for

UX- & industrial-designer, prototyper. Not necessarily in that order.