#API #CODETutorial: Turn Youtube videos to Instagram story posters.15 April 2021

In this tutorial we’ll use the Glitterly API to build a tiny app where users can paste the URL of a Youtube video - and our app will generate a beautiful retro themed Instagram story poster from the URL.

You can follow the tutorial here, or directly check out the project onGitHub.

Try out a live version of the app here.

The final app

How the app will work:

  • The user pastes a Youtube URL
  • Our server will fetch metadata from the URL
  • We'll pass the metadata to the Glitterly API, and create a customised image

What is URL metadata?

URLs contain metadata that describe what this website is about. When you send a link over e.g. WhatsApp often you'll see an image, header and a description in a card about the URL, this is the URLs metadata.

If you want a visual way to see what the metadata a specific URL has check out metatags.io.

1. Setup

The app will be built with Next.js and the back-end will be a tiny Next.js serverless API function.

First initialise a new Next.js project:

npx create-next-app

Install dependencies

npm i axios
npm i html-metadata-parser

We’ll use Axios to make requests to our server. Axios is “isomorphic”, which just means that it can be used on both the server and the client (the browser).

For fetching and parsing the metadata from a URL, we'll use html-metadata-parser. What we want is the name of the youtube video, the sitename and the thumbnail image.

2. Create our serverless function

Next.JS has a special folder called /api. All files added here are tiny servers that you can use as a back end for your Next.js apps. Under the hood, the files you add here are turned into AWS lambda functions.

Add a new file here called image-maker.js


// pages/api/image-maker.js
export default (req, res) => {
     res.status(200).json({ status: 'Hello world' })
}

To this endpoint the user will send a URL string of a youtube video. From this URL we want to get the metadata (for generating our customised image).

For this, we'll use html-metadata-parser


const MetadataParser = require('html-metadata-parser')

export default (req, res) => {
    const { url } = req.body
    const parser_result = await MetadataParser.parser(url)
    const { meta, og } = parser_result
    ...
}

3. Create the image with the Glitterly API

Sign up or log in with your existing account to Glitterly. Go to the dashboard and select this template:

Glitterly API template

For this template, the layers we can change through the API are:

  • video_title
  • site
  • thumbnail

Copy these and the template_id.

Template API layers

We'll change these layers with the URL metadata that we get from step 2.


    const changes = [
        {
            layer: 'thumbnail',
            url: og.images[0].url,
        },
        {
            layer: 'video_title',
            text: meta.title,
        },
        {
            layer: 'site',
            text: og.site_name,
        },
    ]

And send them as an API request with axios to the Glitterly API. The API will create the image for you.

Add your api key, you can find it under your account, and the template_id.


    import { post } from 'axios'

    ...
    const config = { headers: { 'x-api-key': MY_GLITTERLY_API_KEY } }
    const { data } = await post(
        'https://www.glitterly.app/api/image',
        { template_id: MY_GLITTERLY_TEMPLATE_ID, changes },
        config
    )

Woohoo, you created a serverless function that connects with the Glitterly API! Here is the final result:


import { post } from 'axios'
const MetadataParser = require('html-metadata-parser')

// replace this with your API_KEY
// This key only works for one template
const MY_GLITTERLY_API_KEY = '740c1108-8305-4494-9b46-544131f7cc2c'
const MY_GLITTERLY_TEMPLATE_ID = 'OfkWF5Osc11PyNGsMz7E'

export default async (req, res) => {
    const { url } = req.body
    const parser_result = await MetadataParser.parser(url)
    const { meta, og } = parser_result

    const changes = [
        {
            layer: 'thumbnail',
            url: og.images[0].url,
        },
        {
            layer: 'video_title',
            text: meta.title,
        },
        {
            layer: 'site',
            text: og.site_name,
        },
    ]

    const config = { headers: { 'x-api-key': MY_GLITTERLY_API_KEY } }
    const { data } = await post(
        'https://www.glitterly.app/api/image',
        { template_id: MY_GLITTERLY_TEMPLATE_ID, changes },
        config
    )

    return res.status(200).json({ status: 'success', url: data.url })
}


If you want to customise more than text of this template, you can find all the API options in the API documentation.

4. Create a basic UI

The UI consists of a form with an input field and a submit button. When the user clicks the button a request will be sent to our server with the URL that the user pasted.

const Form = () => {
    const [poster_image, setPosterImage] = useState('')
    const [url, setUrl] = useState('')

    const onCreateImage = async (e) => {
        e.preventDefault()

        try {
            const { data } = await post('/api/image-maker', { url })
            setPosterImage(data.url)
        } catch (error) {
            const err_msg = error.response?.data?.status || 'Something went wrong'
            setError(err_msg)
        } finally {
            setFormState(FORM_STATE.DEFAULT)
        }
    }

    return (
            <section className={styles.section}>
                <h1 className={styles.header}>
                    <span role="img" aria-label="lightning">
                        ⚡️
                    </span>{' '}
                    Paste a Youtube URL
                </h1>
                <form onSubmit={onCreateImage}>
                    <label className={styles.label} htmlFor="youtube-url">
                        Url:
                    </label>
                    <div className={styles.inputwrapper}>
                        <input
                            type="text"
                            id="youtube-url"
                            name="youtube-url"
                            className={styles.input}
                            placeholder="Youtube URL"
                            value={url}
                            onChange={(e) => setUrl(e.target.value)}
                        />
                        <button className={styles.button} type="submit">
                            Create Poster
                        </button>
                    </div>
                </form>
            </section>
    )
}

The component is missing error handling, styling, validation and loading. Implementing these will be your challenge! (or you can grab them from github).

And we're done!

Great success! For bonus points you can add a download button to make it easy for the user to download the poster.

Bonus: As you might have noticed, this will work with other URLs as well 🤯 as long as the url has the description, site and OG image meta-data.

Retro Instagram Story Template

Let our API create your images

Sign up to get your free API Key

Get Started