Creating a widget with Meteor

I’m interested in implementing a widget that others can use on their own sites. Similar examples are things like Intercom or Drift.

While this isn’t Meteor specific, I would like information in context with Meteor, as that’s what i’m currently building with. How would one implement a widget like the examples above? Does anyone know of any good examples or tutorials?

I’d also be interested in learning if it’s possible to write the widget itself in React, and if so, how does the end user implement it into their own page?

Not sure about something as complicated as what you’ve linked to, but I’m currently working on implementing a basic signup widget.

The code for the widget is served through the public folder, and the widget posts data to a server-side route, where the data is authenticated and then stored.

I honestly searched for quite a while for best practices but was also unable to find any. Regarding React, I can’t really speak to that, as our widget code simply appends a basic html form to the page.

Im interested in learning how the process of generating the actual widget code that the end user puts into their page is done. Eg, if the widget needs to be customized for their account.

Well you have to remember that you need to serve up a public script somewhere, if you’re going to keep your user’s embed experience relatively painless. If you’re doing account-specific actions, then you’d need a few trips back and forth between your widget script and your app.

The actual widget code depends on what happens in your public script. For example, in our simple signup widget, the embed code looks like:

<div id="our-custom-signup-form"></div><script src="https://ourdomain.com/signup.js?widgetId=someId" type="text/javascript"></script>

Our public signup.js script looks at the widgetId, the origin, and then appends the form to the our-custom-signup-form div. It also attaches a submit handler that posts to our server-side route.

Our widget is relatively benign, in that its only one, very specific task, and we also employ a schema to only allow for strings coming into the db.

Hope this helps!

Thanks for the info. I noticed that the examples I linked both used iframes. Are they just loading an entire separate app?

I just chuck the whole app in an iframe. Works fine, but not very scalable. Especially if someone embeds the widget on a page that gets a lot of traffic. Sounds line @vigorwebsolutions approach of putting assets in the public folder would scale a whole lot better.

How would you write the views for the widget so that they are available through /public? Eg, is there some way to write the widget views in React and somehow compile that in javascript which the user can include?

These are two different approaches. @babrahams is saying that you can basically just run your app (hosted at http://yourdomain.com) in an iframe. This would obviously give you access to the login system, etc., but also comes at the price of spinning up your app in an iframe. With a small or standalone app, this could definitely work, but if your app’s playload is over 1mb, I feel like an embed could negatively affect the user experience for the site where your embed lives.

My main app (written in Meteor) is not the app I want to load into an iframe. The meteor application contains the dashboard and user functionality, among other things.

Are you suggestion I write and then host a completely seperate app to act as the ‘widget’ portion, and then stick that in an iframe?

I got some tips from elsewhere and was told I could write the widget in React (which i’ve done) and then build it and somehow make that bundle available. I am not sure how to do that.

Currently, I just built some React views in a /widget directory and am just calling ReactDOM.render() to render it to another div, alongside the .render() for my current Meteor app.

It’s tough to tell, especially without a concrete use case. You could spin up a node server with some basic http functionality that could serve your iframe content. Or you could make a script publicly available and depend on that. Like I said, there aren’t many “best practices” out there, I think because the practice depends so largely on the use case.

My use case here is basically a chat widget, very similar to the examples I mentioned (Drift, Intercom). They both seem to be using iframes in some capacity, but it’s difficult to follow the logic of the minified scripts.

Drift has you include a script, which seems to create a <script> element to https://js.driftt.com/include/somelargenumber/userid.js. That script in turn looks like it creates an iframe, which sets this: https://js.driftt.com/dist/index-prod.html as its src. That iframe in turn has another script.

Intercom is even more complicated.

As far as strategies for getting your code on someone else’s page, I built my widget based largely on the practices/recommendations from this article.

Also, to save you some hassle – if you are targeting IE users, you will have difficulty in parsing params built into a url, as the support for currentScript is pretty terrible, even with a polyfill. You will be better off passing params as data props of a div:

<script src="http://yourdomain.com" type="text/javascript"></script>
<div id="your-embedded-widget" data-widgetid="someId" data-size="leaderboard"></div>

So I managed to get something working.

I wrote a small React app and through it in imports/widget. I created an index.jsx file and simply called:

ReactDOM.render(
  <Widget/>,
  document.getElementById('widget-target')
);

I then got a webpack configuration setup, and had it spit out a bundle in /public. I could then add a script tag on another app with a <div id="widget-target"></div> tag. The generated bundle would mount on the div.

It seems to of worked, but I am still curious if doing something like this carries any security implications. In addition, how would you add some sort of user identity into the widget? Eg, Each user of the widget should have a user account on the main app. How is something like that to be included?

I think you just need to examine your cost/benefits and use cases. Any time you’re working with something like widgets, you’re always going to have security concerns. The way I think about some of our use cases:

  1. Pulling publicly available data from our db (e.g., a feed of articles from our site)
  2. Pushing data to our db (e.g., a newsletter signup form)
  3. Accomplishing user-authenticated actions (e.g., displaying content to a user signed in via a widget)

In example 1, we are only pulling information from our app, and that information is already publicly available, so the security issues here are minimal.

In example 2, we are pulling and pushing to our app, so we have increased security issues here. We use a schema to ensure that we are only working with strings, and we match our widget origin with the header data to ensure that we are seeing widget data from the website that was intended. We also use a honeypot and some other internal measures to help weed out bots.

In example 3, we are into user auth via a widget, and to me, this is where you need an iframe. I’d probably spin up a microservice with whatever functionality I’m looking to accomplish here, as bundling a client-facing app and serving it into an iframe probably isn’t going to be a good experience.

tl;dr: There are inherent security concerns to serving up code on someone else’s site. Cost/benefit determines how you mitigate those concerns.

So heres a question: what is the best way to communicate from my React widget to the Meteor backend? REST API? Socket.io/PubNub?

orbyt,
Please explain in more detail your approach.
I would like to experiment myself, but I am clueless of how to start.

What i’ve currently done is written a Meteor application which lets users download a widget bundle (written in react and built). The widget uses socket.io to emit and receive messages.

Would you please share some sample code?

I’ve created an Intercom clone, including widget, using Meteor Making a widget is really not hard, but you do not want to do this with Meteor / iFrame Meteor

Here are some general steps to take, but you can DM me if you want to know more.

  • for the widget you just use vanilla js, so no Meteor magic here. Make sure to make it have no dependencies, and try to make it as light-weight as possible. So for example, use Zepto instead of jQuery, PureCSS instead of Bootstrap, no React or other frameworks, etc,

  • you want to use Webpack because that ‘packs’ all your widget code into a single .js which you can load async using some script. This also avoids CORS related issues.

  • you want to use DDP though, there’s an excellent library to connect with your Meteor backend and make your widget reactive (https://github.com/eddiefloreslive/meteor-ddp). Works like a charm.

  • Authentication: In the widget loading script you pass on some unique id that your widget reads and communicates via DDP to Meteor, plus a check on the domain the widget is running. It’s the same as Intercom etc works. You can pass on other data as well

That’s basically it. Good luck

2 Likes