Message Boards Message Boards

Wolfram Notebook Embedder released

Posted 4 years ago

Today, we're happy to officially announce the first version of the Wolfram Notebook Embedder JavaScript library, which allows you to seamlessly embed Wolfram Cloud notebooks on websites. It can automatically resize a container based on the notebook size and it offers an API that can be used to "reach into" the notebook from the outer website, e.g. controlling a Manipulate variable. These things were not easily possible by embedding notebooks using an <iframe>.

HTML page with embedded JavaScript code that embeds a notebook into a given container div

You can read more on the official Wolfram Notebook Embedder website, check out its GitHub repository or install the library from npm. In addition to extensive documentation, the website also contains a few interactive examples for how to use the library.

While we're really excited about this release, it still has some limitations to be aware of (see also the troubleshooting guide):

  • Due to 3rd-party cookie blocking, embedded notebooks don't work very well in the Safari web browser right now. We don't track any personal data using these cookies, but we use them for load balancing, so we can't support certain features without these for now. Depending on the notebook content, you might still have to fall back to using an <iframe> in Safari. We're working on a solution to this (using a different load-balencing strategy).
  • Since the notebook is rendered directly into the DOM of the containing website, CSS definitions are shared between the two worlds and can "bleed" from the outside into the notebook and the other way around, potentially breaking styles in either of them. You might be able to work around such issues by increasing the specificity of your CSS definitions, so they (1) override conflicting definitions coming from the notebook and (2) do not affect the notebook. We're working on a more robust solution, perhaps using a separate Shadow DOM root for embedded notebooks to isolate all styling.

If you encounter any other bugs, please file an issue on GitHub.

This is just the beginning of our initiative to make notebooks easier to embed and interoperate with. Please let us know us what you want to do with this and if you have any questions, ideas or suggestions. One thing we're already starting to work on is an API (e.g. https://www.wolframcloud.com/nb?url=...) that will allow you to render a whole notebook (at a certain URL or with a certain content) on the fly – stay tuned.

POSTED BY: Jan Poeschko
17 Replies

Hi Jan, I’m excited about this direction! I got your examples going and wanted to take a next step – but, I’m stumbling. I use the ReactJS library extensively. When I saw you are using document.getElementById('container') light bulbs started going off somewhere above my head. As you may know React has the primary node into HTML ReactDOM.render(<App/>, document.getElementById("root")), where <App/> is the first component of the react component tree. What I’m interested in doing with import WolframNotebookEmbedder from 'wolfram-notebook-embedder' is add it lower/higher (at any rate exactly where I want) in the React component tree so that a specific React component is ‘responsible’ for container created/managed by WolframNotebookEmbedder. First, I started a project with a create-react-app (CRA) then tried npm install –save 'wolfram-notebook-embedder but this failed. I have the logs if your interested. Second, in index.html, I tried the

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.4.2/react-dom.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.21.1/babel.min.js"></script>
    <script
      crossorigin
      src="https://unpkg.com/wolfram-notebook-embedder@0.1/dist/wolfram-notebook-embedder.min.js"
    ></script>

But this is not working out. Unfortunately, I don’t have much time to start a research and testing process so looking for suggestions/help before proceeding.

Cheers, Mitch

Great you're using React! We're also (happy and heavy) users of React. In fact (as you noticed), the API of the library was inspired by React, i.e.

WolframNotebookEmbedder.embed(url, container);

is intentionally similar to

ReactDOM.render(component, container);

While the embedder library doesn't expose a React component (yet; or maybe it will be another little library that does that at some point), it's definitely meant to allow usage in conjunction with React, and it should be straight-forward to do so. You'd create a wrapper component that renders a single <div> which the notebook can be embedded into, much like described here: https://reactjs.org/docs/integrating-with-other-libraries.html#how-to-approach-the-problem (just call this.embedding = WolframNotebookEmbedder.embed(url, this.el) in componentDidMount and this.embedding.then(nb => nb.detach()) in componentWillUnmount, instead of the jQuery calls in the example there).

In terms of installing the library, using npm (or Yarn) is the right way to go if you have a build/bundle process anyway (which you do, if you're using Create React App). I would only use script tag/CDN-based approach if I didn't have such a process (e.g. in light-weight examples).

I'm not sure why npm install didn't work for you. Attaching the logs would be useful. I just tried in a fresh CRA project, and

npm install --save wolfram-notebook-embedder

works fine for me.

POSTED BY: Jan Poeschko

Hi Jan, this is great!

I've been struggling to integrate WolframNotebookEmbedder with React. From what I understand did you mean something like this:

import React from 'react';
import WolframNotebookEmbedder from 'wolfram-notebook-embedder';

class NotebookEmbed extends React.Component {
  constructor(props) {
    super(props);
    this.embeddingElem = React.createRef();
  }

  componentDidMount() {
    const embeddingElem = this.embeddingElem.current;
    this.embedding=WolframNotebookEmbedder.embed('https://www.wolframcloud.com/obj/jpoeschko/Public/BasicExample.nb', embeddingElem);
  }

  componentWillUnmount() {
    this.embedding.then(nb => nb.detach());
  }

  render() {
    return <div className="NotebookEmbed" ref={this.embeddingElem} />;
  }
}

export default NotebookEmbed;

I keep getting Uncaught TypeError: Cannot read property 'embed' of undefined at NotebookEmbed.componentDidMount errors with this..

Which I believe suggests it's a context issue? Perhaps related to this?

Not entirely sure why I had to import like this (new to React), but if anyone stumbles upon this - I indeed got this working using a CRA with react:17.0.1, react-dom:17.0.1, and wolfram-notebook-embedder:0.2.1 :

import React from 'react';
import * as WolframNotebookEmbedder from 'wolfram-notebook-embedder';

class NotebookEmbed extends React.Component {

  componentDidMount() {
    this.embedding=WolframNotebookEmbedder.embed('https://www.wolframcloud.com/obj/jpoeschko/Public/BasicExample.nb', this.el);
  }

  componentWillUnmount() {
    this.embedding.then(nb => nb.detach());
  }

  render() {
    return <div className="NotebookEmbed" ref={el => this.el = el} />;
  }
}

export default NotebookEmbed;

This has the potential of being a really big deal for users, and therefore for Wolfram. GREAT JOB Jan!!!

The documentation appears to be missing a closing > on the embed script. And the examples are overly simplistic. They should include an actual running example with the Astronomy calculator for example! Also all those images for the code that needs to be used cannot be copied and pasted!!! need the copyable code in those documentation pages...

I am trying to get this to work in Google Site. So far no luck. Could someone paste here the code needed to make this work?

I tried:

<script crossorigin src="https://unpkg.com/wolfram-notebook-embedder@0.1/dist/wolfram-notebook-embedder.min.js"></script>

<div id="notebookContainer"></div>

<script WolframNotebookEmbedder.Embed('https://www.wolframcloud.com/obj/luc.barthelet/mynotebook.nb', document.getElementById('notebookContainer')
);></script>

Thanks again for doing this, really want to use it ASAP,

Luc

POSTED BY: Luc Barthelet

Thanks for your feedback, Luc!

Spot-on regarding the closing >. We'll fix that.

The point of the image on the first page is really just a "teaser" and overview of how the library operates; it's (deliberately) not even the complete HTML code for what you see on the right. More examples are on https://reference.wolfram.com/language/WolframNotebookEmbedder/examples/ and it should be easy to copy and paste code from there. The first example is intentionally simplistic to focus on the very basics; the following ones add a bit more complexity.

I agree that using a more sophisticated notebook (such as the Astronomy Clock shown on the landing page) would perhaps be more impressive, but at the same time, it wouldn't change the actual HTML or JS code, so there's a trade-off with distracting from what's essential for embedding... So I think we'll add another "neat" example.

In general, I agree we could and should add many more examples. Of course, since it's open source, anyone's welcome to help: Just open a pull request with changes to https://github.com/WolframResearch/wolfram-notebook-embedder/blob/master/website/pages/en/examples.js

Regarding your code: When I try to open https://www.wolframcloud.com/obj/luc.barthelet/mynotebook.nb I only get a 404 page. Maybe the notebook is not public? (Being public is a prerequesite for a notebook to be embeddable.) Also, instead of

<script                         
WolframNotebookEmbedder.Embed('https://www.wolframcloud.com/obj/luc.barthelet/mynotebook.nb',
document.getElementById('notebookContainer')
);></script>

you'll need

<script>
WolframNotebookEmbedder.embed(
    'https://www.wolframcloud.com/obj/luc.barthelet/mynotebook.nb',
    document.getElementById('notebookContainer')
);
</script>

(note the closing > and .embed instead of .Embed). Please let us know if you still run into problems after these changes.

POSTED BY: Jan Poeschko

Awesome, it works now. I just need to learn how to just get the last manipulate to show up rather than the full notebook!

POSTED BY: Luc Barthelet

It would be good if the Wolfram Notebook Embedder was installed on the Wolfram Community website and automatically worked for the Mathematica Stack Exchange.

And what would be really nice if it worked with Facebook and LinkedIn so as to make embedding Notebooks as easy as possible.

POSTED BY: Paul Abbott

Embedding in Facebook or Linkedin for you would be risky, in terms of cost, since anyone seeing it would end up charging your account...

POSTED BY: Luc Barthelet

Yes, integrating notebooks in Wolfram Community using this embedder library is already in progress. We're also working on an oEmbed endpoint, which will help e.g. with WordPress and maybe even Stack Exchange (?).

POSTED BY: Jan Poeschko
Posted 4 years ago

Hi Jan,

This is great news. Thank you.

Could this also be used to render static HTML of notebooks in Github repositories. Similar to Jupyter notebook rendering.?

POSTED BY: Rohit Namjoshi

Could this also be used to render static HTML of notebooks in Github repositories.

Good point, and yes, potentially – although the library itself is mostly about interactive rendering (on the client side). To retrieve static HTML for a (cloud) notebook, we have the /statichtml API described here: https://reference.wolfram.com/language/WolframNotebookEmbedder/docs/ServerSideRendering/

The primary purpose of this API is to speed up loading of embedded notebooks and to help with SEO, though. E.g. it currently doesn't include the content of all cells (only up to a certain vertical threshold, plus simple textual cells). We'll expand this in the future.

POSTED BY: Jan Poeschko
Posted 4 years ago

Glad to see this is finally out. One big question: I'd like to render arbitrary chunks of Mathematica code, but don't necessarily want to make a cloud notebook for each one. Anyway to get around this? Interactivity in terms of things like Manipulate doesn't matter to me, but I'd like Graphics3D to work.

POSTED BY: b3m2a1 ​ 

I'd like to render arbitrary chunks of Mathematica code, but don't necessarily want to make a cloud notebook for each one.

This should be addressed by the on-the-fly notebook rendering API (maybe of the form https://www.wolframcloud.com/nb?url=...) that I mentioned above. It could also take literal notebook content (a notebook/cell/box expression) as an argument, e.g. https://www.wolframcloud.com/nb?content=.... I won't make any promises when it's going to be there, but it's definitely something we want as well.

In the meanwhile, you could build something a bit like this API yourself, generating a cloud object based on the content expression passed in. You could use a hash of the expression as an identifier, avoiding unnecessary duplication. The API would return the final cloud object URL, which you could then feed into the embedder library. You could enable rather long (browser) caching for the API so it wouldn't have to be executed on every visit. Just be aware that there are some security challenges with this (e.g. you'd have to make sure there are no dangerous Dynamics in the notebook created under your account).

POSTED BY: Jan Poeschko
Posted 4 years ago

Very nice! My understanding of "cloud credits" is near zero. Do we get "charged" for each time someone uses an embedded notebook?

POSTED BY: Jim Baldwin

Currently, you get charged cloud credits for any kernel evaluations the notebook needs, e.g. to resolve a Dynamic or to update a Manipulate after moving a slider. Just viewing a notebook without any dynamic content (e.g. a notebook with only text in it) would not consume any credits.

This page has some relevant numbers: https://www.wolfram.com/cloud-credits/

You can see your currently available number of credits by evaluating $CloudCreditsAvailable (either in the cloud or on desktop).

That being said, the way we charge credits in deployed notebooks will change rather soon (to the better!): Dynamics and interactivity up to a certain (rather generous, per-viewer) limit will be free, and beyond that you'll be able to choose whether you actually want to pay credits or offer the viewer different options (e.g. they could sign in and make their own copy of the notebook, thus not consuming your credits). More details coming when we're closer to making this change.

POSTED BY: Jan Poeschko

Your remark about how credits will be charged in deployed notebooks caught my eye. Has there been any development in this direction since your post from last year? So far those few sentences are the only information I've been able to find in that vein.

POSTED BY: Michael Janas
Reply to this discussion
Community posts can be styled and formatted using the Markdown syntax.
Reply Preview
Attachments
Remove
or Discard

Group Abstract Group Abstract