How to Use Open Graph to Unfurl URLs into Rich Objects in Chat Apps

By Syed Ahmed

Chat apps have transcended simple 1:1 and group messaging, and chat developers are always looking for ways to take a conversation to the next level, making it more immersive and engaging. Interactive emojis, language translation, or even integrating an AI-enabled chatbot are just a few features driving the next-generation of chat.

At this point, users expect that some of these features should be a native part of the application. And one of those features is rich cards/rich objects, the unfurling of simple URLs into interactive messages. It’s a feature you don’t know you love until it’s not there.

In this blog post, we’ll walk you through integrating rich objects in a ChatEngine app using our Open Graph plugin.

Open Graph Comparison

Creating the Initial React Project

Let’s start off by creating our React project using the create-react-app in our terminal/command-line.

npx create-react-app open-graph-project
cd open-graph-project
npm start

The above lines of code create our project, then change our directory into the project that we just created. Then the next command will run your project on http://localhost:3000.

Creating the Frontend with Material Design

This is an optional step and you can create the frontend however you like, but for now, we’ll create a simple chat component that allows everyone to chat and shows the chat feed. If you feel like you’ve already got this nailed down, I’ve posted the base code on my GitHub so you can pull from the “base” branch and move on to the next step.

Let’s begin by deleting the App.js file. We don’t really need it and we’ll be able to do everything in our index.js for this example.

We’ll create a card component which will house our chat messages and have an input box which allows the user to send messages. Using the material-UI library for React, our index.js file will something like this:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import { withStyles } from '@material-ui/core/styles';
import Card from '@material-ui/core/Card';
import CardActions from '@material-ui/core/CardActions';
import CardContent from '@material-ui/core/CardContent';
import List from '@material-ui/core/List';
import ListItem from '@material-ui/core/ListItem';
import Button from '@material-ui/core/Button';
import Typography from '@material-ui/core/Typography';
import Input from '@material-ui/core/Input'; const styles = { card: { maxWidth: 345 }, openCard:{ maxWidth: 200 }, openMedia: { height: 80, }, media: { objectFit: 'cover', }, container: { display: 'flex', flexWrap: 'wrap', },
}; class App extends Component { constructor(props) { super(props); this.state = { messages: [], chatInput: '' }; } sendChat = () => { // Logic for sending chat } setChatInput = (event) => { this.setState({ chatInput: }) } componentDidMount() { } handleKeyPress = (e) => { if (e.key === 'Enter') { this.sendChat(); } } render(){ const { classes } = this.props; return( <Card className={classes.card} > <CardContent> <Typography gutterBottom variant="headline" component="h2"> Messages </Typography> <div className={classes.root}> <List component="nav"> <ListItem> <Typography component="div"> messages will go here </Typography> </ListItem> </List> </div> </CardContent> <CardActions> <Input placeholder="Enter a message" value={this.state.chatInput} className={classes.input} onKeyDown={this.handleKeyPress} onChange={this.setChatInput} inputProps={{ 'aria-label': 'Description', }} /> </CardActions> </Card> ); } } const ChatComponent = withStyles(styles)(App);

Before we can get the base project running, we’ll need to install material-ui:

npm install @material-ui/core

Getting Your API Key from

This ChatEngine plugin uses, a service built on the Open Graph protocol. Simply signup for the service, and get your keys from your dashboard.

Configuring ChatEngine

Additionally, you’ll need to configure ChatEngine and get your pub/sub keys. You can do this directly in the form below.

Once your keys are generated, you can begin by initializing the client. Install the related packages to start developing.

npm i chat-engine chat-engine-open-graph

Next, edit the index.js file to integrate ChatEngine.

import ChatEngineCore from 'chat-engine';
import opengraph from 'chat-engine-open-graph'; const now = new Date().getTime();
const username = ['user', now].join('-'); const ChatClient = ChatEngineCore.create({ publishKey: 'pub-c-3f89be1a-7cca-4307-8884-80b5b4855b23', subscribeKey: 'sub-c-83c785b0-b219-11e8-acd6-a622109c830d'
}, { globalChannel: 'chatting'
}); ChatClient.connect(username, { signedOnTime: now
}, 'auth-key');

Then adjust your App component in index.js your  file to send and receive messages.

class App extends Component { constructor(props) { super(props); = new ChatClient.Chat(`openGraph`);{ api: (url) => `${encodeURI(url)}?app_id=${apiKey}`, })); this.state = { messages: [], chatInput: '' }; }
// ... More code

In the constructor, we’ll create a new chat with the name “openGraph” then add the Open Graph plugin which we installed and imported earlier. In here we’ll define the endpoint which will have our API key which we grabbed earlier and the URL of the website.

class App extends Component {
// ... Code as shown above sendChat = () => { if (this.state.chatInput) {'message', { text: this.state.chatInput, uuid: username }); this.setState({ chatInput: '' }) } } setChatInput = (event) => { this.setState({ chatInput: }) } componentDidMount() {'message', (payload) => { const { data } = payload; console.log(data); let messages = this.state.messages; if(data.img != null){ messages.push( <div key={this.state.messages.length} style={{border: "1px solid grey"}}> { data.uuid }: <img src={data.img} alt={data.title}/> <h3> { data.title } </h3> <a href={ data.url }> link </a> <p> { data.desc } </p> </div> ); }else{ messages.push( <Message key={ this.state.messages.length } uuid={ } text={ }/> ); } this.setState({ messages: messages }); }); } handleKeyPress = (e) => { if (e.key === 'Enter') { this.sendChat(); } }

The sendChat function was empty earlier but now it will emit a message with the text we enter in the input and also send the username, which we created earlier, with the date.

In the componentDidMount function, we’ll listen for new messages and once we get the new message we’ll check if that message has an image property. If it does then we’ll render it as a rich message that has the properties from Open Graph. Otherwise, show the message as normal.

class Message extends Component{ render () { return ( <div > { this.props.uuid }: { this.props.text } </div> ); }
}; class App extends Component{
// ... Code from component as discuessed above render(){ const { classes } = this.props; return( <Card className={classes.card} > <CardContent> <Typography gutterBottom variant="headline" component="h2"> Messages </Typography> <div className={classes.root}> <List component="nav"> <ListItem> <Typography component="div"> { this.state.messages } </Typography> </ListItem> </List> </div> </CardContent> <CardActions> <Input placeholder="Enter a message" value={this.state.chatInput} className={classes.input} onKeyDown={this.handleKeyPress} onChange={this.setChatInput} inputProps={{ 'aria-label': 'Description', }} /> <Button size="small" color="primary"> Github </Button> <Button size="small" color="primary"> Article </Button> </CardActions> </Card> ); } } const ChatComponent = withStyles(styles)(App); ChatClient.on('$.ready', () => { ReactDOM.render(<ChatComponent />, document.getElementById('root'));

In the render function, we’ll have the logic to populate new messages. We also need to make sure that before we render the component we check for the $.ready event.

Working example open graph

Great! now we have our ChatEngine app running with Open Graph!

If for some reason the code above doesn’t work for you, download the master branch and get it running with the following commands:

mkdir open-graph-demo
cd open-graph-demo
git init
git pull master
npm i
npm start

Wrapping Up

We hope you enjoyed our tutorial on unfurling and enriching URLs in the chat feed. For all our plugins, and a ton of other ChatEngine tutorials and demos, check out our docs and tutorials.