Over the years, chat applications have been frequently used by people in private and group channels to communicate through sending and receiving texts, media assets, and links to external resources. When sharing a link in a chat conversation, how would the receiver know where the unknown link redirects to before opening it? Through a URL Preview.
URL Previews do not happen automatically, hence, you need to implement it within your application. This tutorial will first explain the URL preview feature and how it improves the user experience of a collaborative application. The tutorial will also provide you with a hands-on demonstration of how to generate URL previews through the /embed endpoint within the Weavy Web API.
A URL Preview retrieves rich data points such as an image, page title, and description from the metadata of an external website and renders them in a digestible format for users when a link is added to a message.
Link previews are important for increasing the Click-Through-Rate (CTR) within an application and it also improves the application’s User Experience (UX) as users get a quick glimpse of the link’s content before opening it. E-commerce websites are leveraging link previews to boost product sales as they display key data points like a product’s price and quantity alongside a Call To Action link within a generated preview for buyers to make a quick decision.
When implementing a URL Preview, developers have two main options: either retrieve the target website’s HTML document and parse it manually to extract the preview data or use third-party services to extract the data. A preview can also be generated and stored either when the sender inserts the link or when the receiver gets a message containing a URL.
The following are three API Services used for URL previews;
In addition to API services, there are libraries that abstract the url preview extraction process. All you need to do is to provide a target URL and they will return the preview data for it. Examples of these libraries include link-preview-js for JavaScript and UrlPreview for .NET applications.
While a URL preview feature is invaluable, there are several challenges and edge-case scenarios that developers are bound to face during its implementation. Let’s consider three of these challenges:
Despite being a relatively minor feature, security researchers have highlighted ways the logic used for implementing a URL preview could unintentionally violate a user’s data privacy.
Developers building chat apps promising end-to-end encrypted communication will be violating their user’s privacy by using third-party API services to generate URL previews as the shared links could lead to sensitive documents that should be kept private.
When previews are generated on the message receiver’s end, there is the possibility of a malicious user reverse-engineering the feature to extract another user’s browser details such as the IP address because the unknown link is automatically opened by the app to generate a preview, even if it contains malicious code.
The CORS mechanism controls access to the resources within a website such as fonts from a different domain as a security measure. Websites without a proper CORS configuration will make it difficult to generate a URL preview as the page metadata will be inaccessible due to the CORS protection.
The next sections within this tutorial are hands-on to guide you through the process of building a React.js application. To follow along, you will need to have;
Open your Weavy web dashboard to either create an environment or use an existing one for the demo application.
Next, you need to either create or obtain an existing API Key to authenticate the API requests you will make to create resources within your Weavy environment.
Click the Generate API Key button to begin the process of creating an API Key.
Provide a Name and Expiration value within the launched Generate API Key modal, then click the Generate Key button to create the key.
After completing the guide, you will find your credentials on the Weavy environment page as shown in the image below;
Take note of the URL and Key values as you will make use of them over the next steps.
Launch the terminal or command prompt application on your computer as you will execute various cURL commands to create resources within your Weavy environment.
Execute the command below to create a Chat app type within your Weavy account. Make sure to replace the WEAVY_DOMAIN
and WEAVY_KEY
placeholders with the corresponding credentials from the Weavy dashboard. Replace the PROJECT_NAME
placeholder with a preferred name for the Weavy application.
curl {WEAVY_DOMAIN}/api/apps \
-H "Authorization: Bearer {WEAVY_API_KEY}" \
-H "Content-Type: application/json" -d "{ 'uid': 'PROJECT_NAME', 'type': 'chat' }"
Take note of the id property within the JSON response from creating the Chat App. You will need to provide it as a URL parameter when interacting with the Weavy Web API.
At this point, you have a functional Weavy account with a Chat app and the authentication key. Let’s proceed to use these resources while building the web application.
Within this section, you will build a demo React.js application to create, retrieve and render the data from the Chat app you created in the previous section. As a demo application, you will only focus on implementing the post and embeds retrieval, then you will use TailwindCSS to rapidly style the application using inline classes.
To begin, execute the command below to create a React.js application named weavy-react-chat-app through the Vite CLI
:
npm create vite@latest weavy-react-chat-app --template react
Open the generated weavy-react-chat-app
project in your preferred code editor. You will have to edit and create new files within the next steps
TailwindCSS is a modern utility-first CSS framework that provides developers with the ability to rapidly style elements through the use of inline classes.
Execute the command below to install the three (3) libraries you need to enable TailwindCSS within the application.
npm install -D tailwindcss postcss autoprefixer react-icons
Execute the next command below to generate a base TailwindCSS configuration within the project.
npx tailwindcss init -p
Open the generated tailwind.config.js
file and replace the content object with the code below to specify code directories for TailwindCSS.
curl {WEAVY_DOMAIN}/api/apps \
-H "Authorization: Bearer {WEAVY_API_KEY}" \
-H "Content-Type: application/json" -d "{ 'uid': 'PROJECT_NAME', 'type': 'chat' }"
Replace the entire boilerplate code within the src/index.css file with the code below to add the TailwindCSS directives and complete the setup.
# weavy-react-chat-app/src/index.css
@tailwind base;
@tailwind components;
@tailwind utilities;
Execute the cURL command below to create a User within your Weavy environment. The cURL command contains an object payload to specify the user’s uid and name values respectively.
curl {WEAVY_DOMAIN}/api/users \
-H "Authorization: Bearer {WEAVY_API_KEY}" \
-H "Content-Type: application/json" \
-d "{ 'uid': 'chat_app_user-01', 'name': 'John Doe'}"
Next, you will add the created user to the Weavy application. This step will ensure that the user can retrieve the contents of the chat application.
Replace the placeholders with their corresponding values and execute the cURL command below to make a PUT request to the /api/apps/{id}/members/{userid} endpoint to add the user to the Weavy application.
curl -X PUT {WEAVY_DOMAIN}/api/apps/{api_id}/members/{user_id} \
-H "Authorization: Bearer {WEAVY_API_KEY}"
Next, you will generate a token associated with the user you created. You will need the token to authenticate the API request from the React app to the Weavy Web API.
Execute the command to execute a POST request to generate an access token for the user you have created. Ensure to replace the placeholders within the POST request as it expects to use the exact uid value specified when the user was created.
curl -X POST {WEAVY_DOMAIN}/api/users/{user_uid}/tokens \
-H "Authorization: Bearer {WEAVY_API_KEY}"
The image shows the response from the POST request containing an access_token property for the token and an expires_in value for the token duration. In a production-ready application, generating a user token should be a part of your authentication flow and the returned value should be stored for subsequent requests in the application.
It is strongly recommended not to use your API Key when interacting with the Weavy API from a front-end client. Instead, use the access_token value generated by a user.
With the user token retrieved, let’s proceed to securely store the credentials needed in a .env file.
Create a .env file at the root directory of the weavy-react-chat-app
project to securely store your Weavy resource credentials separately from the application code.
Replace the placeholders and add your Weavy Domain, User Token, and App ID values to the .env file using the format below:
# weavy-react-chat-app/.env
VITE_WEAVY_DOMAIN=WEAVY_DOMAIN_URL
VITE_WEAVY_ACCESS_TOKEN=USER_TOKEN
VITE_APP_ID=CHAT_APP_ID
Within the weavy-react-chat-app/src
directory, create an api.js
file to store a reusable API client for interacting with the Weavy Web API.
Add the JavaScript code block within the code block below into the api.js
file:
// weavy-react-chat-app/src/api.js
const DOMAIN = import.meta.env.VITE_WEAVY_DOMAIN;
const KEY = import.meta.env.VITE_WEAVY_ACCESS_TOKEN;
export const ApiClient = async ({ endpoint, method, body }) => {
if (!DOMAIN || !KEY) {
console.error(`Weavy Environment Variables Missing!`);
return;
}
try {
const request = await fetch(`${DOMAIN}/api/${endpoint}`, {
method: method || "GET",
headers: {
Authorization: `Bearer ${KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify(body),
});
return await request.json();
} catch (e) {
console.log(`Error with ${endpoint} endpoint:`, e);
}
};
The asynchronous ApiClient function above uses the browser fetch API to make HTTP requests to your Weavy environment to create or retrieve Chat and embeds. The HTTP requests are authenticated by placing your Weavy API Key within the .env file in the request header.
With the ApiClient
function, you will not need to repeat the fetch logic within the React components. All you will need to do is to pass in the endpoint, method, and body parameters to interact with different endpoints within the Weavy Web API.
Open the existing App.jsx
file within the weavy-react-chat-app/src
directory, You will modify the existing code to fetch and display all items in your Weavy Chat app. The App component will also display a form input element for users to write and submit a new post.
To understand how the App component functions, you will gradually piece it together across multiple steps.
First, add the content of the code block below into the App.jsx file. Although the code is missing a return statement, it uses the ApiClient() function in a useEffect() hook to fetch Chat and store the response in the component's local state.
// weavy-react-chat-app/src/App.jsx
import { useEffect, useState } from "react";
import { BsSend } from "react-icons/bs";
import { ApiClient } from "./api";
import PostCard from "./PostCard";
const APP_ID = import.meta.env.VITE_APP_ID;
const extractUrlFromText = (text) => text.match(/(https?:\/\/[^ ]*)/);
function App() {
const [chat, setAvailableChats] = useState(null);
const [message, setMessage] = useState("");
useEffect(() => {
(async () => {
const chatData = await ApiClient({ endpoint: `apps/${APP_ID}/messages` });
setAvailableChats(chatData?.data);
})();
}, []);
const handleSubmit = async () => {
const extractedUrl = extractUrlFromText(message);
let embedId = null;
if (extractedUrl) {
const createEmbedData = await ApiClient({
endpoint: `/embeds`,
method: "POST",
body: {
url: extractedUrl[0],
},
});
embedId = createEmbedData?.id;
}
const createChatData = await ApiClient({
endpoint: `apps/${APP_ID}/messages`,
method: "POST",
body: {
text: message,
embed_id: embedId,
},
});
setAvailableChats(Array.isArray(chat) ? [...chat, createChatData] : [createChatData]);
setMessage("");
};
// ADD RETURN STATEMENT HERE
);
}
export default App;
Of interest in the code above is the handleSubmit()
function that will be executed at the click of a button. Through the steps outlined below, the handleSubmit()
function handles submitting a post and generating a URL preview using the Weavy /embed endpoint.
ApiClient()
will be used to make a POST HTTP request to the /embed endpoint to create an embed and the id property returned in the embed response will be stored in the embedId
variable.Add the next block of code containing a return statement into the App component right within the section presently labeled "ADD RETURN STATEMENT HERE"
// weavy-react-chat-app/src/App.jsx
return (
<div className="flex w-full bg-gray-100 h-full justify-center">
<div className="max-w-[650px] shadow m-auto h-full bg-[white] w-full ">
<div className="bg-gray-200">
<h1 className="text-center py-4 text-xl font-semibold">Weavy URL Preview Chat</h1>
</div>
<div className="px-6">
<div>
{chat && (
<ul>
{chat.map(({ text, id, embed, created_at, created_by }) => (
<li className="my-8" key={id}>
<PostCard {...{ text, embed, created_at, created_by }} />
</li>))}
</ul>
)}
</div>
<br />
<form className="border h-[60px] w-full flex">
<div className="w-full bg-gray-100 flex items-center">
<input
value={message} onChange={(e) => setMessage(e.target.value)}
placeholder="Enter A Message"
className="p-4 w-full"
/>
</div>
<div
onClick={() => handleSubmit()}
className="flex mx-4 text-3xl items-center cursor-pointer"
>
<BsSend />
</div>
</form>
</div>
</div>
</div>
);
The code above renders the application layout with a header, a list of retrieved Chat, and an input form with a submit button.
The App component above is using a PostCard
component which does not exist yet within the project. Let’s create it!
Create a PostCard.jsx
file within the weavy-react-chat-app/src/
directory.
Add the content of the code block below into the PostCard.jsx
file to build the PostCard
component. The PostCard
component will display each Post within your Weavy app using data passed in as props from the parent App component.
import React from "react";
import { AiOutlineLink } from "react-icons/ai";
const truncateText = (text, length) =>
text.split(" ").slice(0, length).join(" ");
const PostCard = ({ text, embed, created_at, created_by }) => (
<div className="rounded overflow-hidden shadow-lg mt-4 bg-white ">
{embed && (
<div className="flex row bg-gray-100">
{embed?.image && (
<img
className="w-[150px] h-[100px] object-cover"
src={embed.thumbnail_url}
alt={embed.title}
/>
)}
<div className="ml-4 flex items-center py-1">
<div>
<a target={"_blank"} rel="no-opener" href={embed.original_url}>
<p className="font-semibold"> {embed.title} </p>
</a>
<p> {truncateText(embed.description, 10)}... </p>
</div>
</div>
<div className="ml-2 mr-2 mt-1 text-2xl">
<AiOutlineLink />
</div>
</div>
)}
<div className="px-2 py-4">
<p className="text-xl mb-4 font-semibold ">{text}</p>
<p className="text-gray-500 mb-2">
Posted By <b> {created_by.display_name} </b> On{" "}
<b>{new Date(created_at).toLocaleDateString()} </b>
</p>
</div>
</div>
);
export default PostCard;
The PostCard component uses conditional statements to handle cases where a Post does not contain a preview or a preview does not have a thumbnail. The preview card also uses an anchor element with the extracted URL attached to the text to enable users to open the link in a new tab.
The demo application uses the description property within the embed object to display the link preview description. If you want to display the rich objects within a preview, you may consider using the iframe property value which contains parsed HTML.
At this point, you have finished building the demo application for trying out URL previews with Weavy. Let’s proceed to start the Vite server and try out the React application.
Execute the command below to start and serve the React application on your localhost;
npm run dev
Open your web browser and navigate to the running application at http://127.0.0.1:5173/.
Type in a post with a link, then click the icon to submit the post. Try creating a post again without a link to have a combination of Chat with and without link previews as shown in the image below.
The image below shows three Chat. Two have link previews generated from the URL within the post text and only one has a thumbnail from the link preview.
Select what technology you want to ask about
Get answers faster with our tailored generative AI. Learn more about how it works
This is a custom LLM for answering your questions. Answers are based on the contents of the documentation and this feature is experimental.
To access live chat with our developer success team you need a Weavy account.