Use Line Front-end Framework (LIFF) to enrich your bot
Tags: line, linebot, liff
Published: 2018-10-12 01:37:55

---
title: Use Line Front-end Framework (LIFF) to enrich your bot
published: true
description: This article explains how to use LIFF.
tags: LINE, LINEBOT, LIFF
cover_image: https://developers.line.me/media/liff/overview/viewTypes-4cb714f3.png
---


# Overview

In this article, I explain how to develop a web page by using Line Front-end Framework (LIFF) SDK and enrich your bot, as well as how to use CLI too for LIFF.

I re-use some code from [line-liff-starter](https://github.com/line/line-liff-starter) repository.
The final version is hosted at [here](https://github.com/kenakamu/LINE-LIFF-Sample/)

# LIFF application
It's a just another html page with javascript with LIFF SDK, which is registered by using LIFF API to generate unique URL to be used in LINE app.


### Prerequisites

- Basic understanding of LINE Bot
- [Visual Studio Code](https://code.visualstudio.com/)
- [Azure Subscription](https://azure.microsoft.com/ja-jp/free/)
- [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest) 
- [git](https://git-scm.com/download)
- [LIFF CLI](https://qiita.com/kenakamu/items/5a9cbdc32c4575e53c59)

※ Even though I use Microsoft Azure to host my page, you can host it anywhere.

# Prepare the environment first

### Create "Channel" in LINE Developer Portal

Create Messaging API channel in LINE Developer portal, and get channel and token keys.

<img src="https://qiita-image-store.s3.amazonaws.com/0/214116/d63d4afe-08e3-e383-bd53-111dee845ea3.png" width=600/>

Please copy and keep "Your user ID" too.

<img src="https://qiita-image-store.s3.amazonaws.com/0/214116/fd5fb84a-e0e8-556d-d1bd-f048f8dfaa51.png" width=600/>

### Create WebApps in Azure Portal

You can use Azure Portal to create a web app, but I use CLI this time for fun.

1\. Install、[Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest), or you can also use "Cloud Shell" on  [Azure Portal](https://portal.azure.com).

<img src="https://qiita-image-store.s3.amazonaws.com/0/214116/7287ecb7-702d-e17d-351c-2304ccf2bc20.png" width=600/>

2\. If you use Cloud Shall, skip to step 4. Otherwise follow the steps to login.


```
az login
```

3\. Follow the instruction on the screen to complete logging in.

4\. Make sure you use right Azure Subscription in case you have some.

```
az account list
az account set -s 'subscription id'
az account show
```
5\. Create resource group. I created "lineliffsample" resource group in East Japan.
```
az group create -n lineliffsample -l japaneast
```

6\. Next, create a application service plan and a WebApps to host LIFF application.

```
az appservice plan create -n lineliffappplan -g lineliffsample --sku F1
az webapp create -n <unique name for WebApps> -g lineliffsample -p lineliffappplan
```

7\. Configure the WebApps to enable git deploy.

```
az webapp deployment user set --user-name <username> --password <password>
az webapp deployment source config-local-git -n <your webapp name> -g lineliffsample
```

### Use LIFF CLI with existing page

You can actually register any page as LIFF. In this section, I explan how to use CLI tool to register a page as LIFF.

1\. Install liff (LIFF CLI tool).

```
npm install -g liff
```

2\. Run liff init to initialize the tool. 

```
liff init <Channel Access Token>
```

3\. Register LIFF application. I use "tall" here but you can try "full" and "compact" as well.

```
liff add https://linecorp.com/en/ tall
```

4\. Get LIFF ID and Accessible URL.

<img src="https://qiita-image-store.s3.amazonaws.com/0/214116/a9469abf-dcba-5d16-cb43-52982a003b35.png" width=500/>

5\. Now, send the address by using "liff send" command or you can even send it via LINE to your friend. It works outside of the bot, too.
```
liff send <LIFF ID> <User ID>
```

<img src="https://qiita-image-store.s3.amazonaws.com/0/214116/dc22e480-0369-1981-ffb8-63b323c02a74.png" width=300 />

# Develop LIFF application

In this section, I explain how to develop LIFF application with LIFF SDK.

### Create a project

1\. Create MyFirstLiff folder and open it via Visual Studio Code.

```shell
mkdir MyFirstLiff
cd MyFirstLiff
code .
```
2\. Create index.html.

![image.png](https://qiita-image-store.s3.amazonaws.com/0/214116/865c2a24-cbe8-ba88-7dfc-2e37a081984c.png)

3\. Copy and paste following code to index.html.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My First LIFF</title>
</head>
<body>
    <div id="liffdata">
        <h2>LIFF Data</h2>
        <table border="1">
            <tr>
                <th>language</th>
                <td id="languagefield"></td>
            </tr>
            <tr>
                <th>context.viewType</th>
                <td id="viewtypefield"></td>
            </tr>
            <tr>
                <th>context.userId</th>
                <td id="useridfield"></td>
            </tr>
            <tr>
                <th>context.utouId</th>
                <td id="utouidfield"></td>
            </tr>
            <tr>
                <th>context.roomId</th>
                <td id="roomidfield"></td>
            </tr>
            <tr>
                <th>context.groupId</th>
                <td id="groupidfield"></td>
            </tr>
        </table>
    </div>
    
    <!-- Load LIFF SDK -->
    <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
    <script src="liff.js"></script>
</body>
</html>
```

4\. Add liff.js in the same directory and paste the followig code.

```javascript
window.onload = function (e) {
    // initialize and get basic information
    // https://developers.line.me/en/reference/liff/#initialize-liff-app
    liff.init(function (data) {
        initializeApp(data);
    });
};

function initializeApp(data) {
    document.getElementById('languagefield').textContent = data.language;
    document.getElementById('viewtypefield').textContent = data.context.viewType;
    document.getElementById('useridfield').textContent = data.context.userId;
    document.getElementById('utouidfield').textContent = data.context.utouId;
    document.getElementById('roomidfield').textContent = data.context.roomId;
    document.getElementById('groupidfield').textContent = data.context.groupId;
}
```

5\. Save all.

### Deploy LIFF Application.


1\. Initialize git. Open the "Integrated terminal" and run git init.

```
git init
```

2\. Add remote which you obtain while creating WebApps above.

```
git remote add origin <remote git address of your WebApps> 
```

3\. Add all and commit.

```
git add .
git commit -m "initial"
```

4\. Push to deploy.

```
git push -u origin master
``` 

5\. Use LIFF CLI to register.

```
liff add <WebApps address> tall
```

6\. Now you can use the LIFF address to test. Make sure you get user ID and language of yourself.

<img src="https://qiita-image-store.s3.amazonaws.com/0/214116/75a77a89-fc54-2a99-6dfc-d1d6e670925f.png" width=300/>

### Get user profile

1\. Replace following code to index.html.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My First LIFF</title>
</head>
<body>   
    <div id="profileinfo">
        <h2>Profile</h2>
        <div id="profilepicturediv">
        </div>
        <table border="1">
            <tr>
                <th>userId</th>
                <td id="useridprofilefield"></td>
            </tr>
            <tr>
                <th>displayName</th>
                <td id="displaynamefield"></td>
            </tr>
            <tr>
                <th>statusMessage</th>
                <td id="statusmessagefield"></td>
            </tr>
        </table>
    </div>

    <div id="liffdata">
        <h2>LIFF Data</h2>
        <table border="1">
            <tr>
                <th>language</th>
                <td id="languagefield"></td>
            </tr>
            <tr>
                <th>context.viewType</th>
                <td id="viewtypefield"></td>
            </tr>
            <tr>
                <th>context.userId</th>
                <td id="useridfield"></td>
            </tr>
            <tr>
                <th>context.utouId</th>
                <td id="utouidfield"></td>
            </tr>
            <tr>
                <th>context.roomId</th>
                <td id="roomidfield"></td>
            </tr>
            <tr>
                <th>context.groupId</th>
                <td id="groupidfield"></td>
            </tr>
        </table>
    </div>
    
    <!-- Load LIFF SDK -->
    <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
    <script src="liff.js"></script>
</body>
</html>
```

2\. Replace code in liff.js.

```javascript
window.onload = function (e) {
    // initialize and get basic information
    // https://developers.line.me/en/reference/liff/#initialize-liff-app
    liff.init(function (data) {
        getProfile();
        initializeApp(data);
    });
};

// Get profile and display
function getProfile(){
    // https://developers.line.me/en/reference/liff/#liffgetprofile()
    liff.getProfile().then(function (profile) {
        document.getElementById('useridprofilefield').textContent = profile.userId;
        document.getElementById('displaynamefield').textContent = profile.displayName;

        var profilePictureDiv = document.getElementById('profilepicturediv');
        if (profilePictureDiv.firstElementChild) {
            profilePictureDiv.removeChild(profilePictureDiv.firstElementChild);
        }
        var img = document.createElement('img');
        img.src = profile.pictureUrl;
        img.alt = "Profile Picture";
        img.width = 200;
        profilePictureDiv.appendChild(img);

        document.getElementById('statusmessagefield').textContent = profile.statusMessage;
    }).catch(function (error) {
        window.alert("Error getting profile: " + error);
    });
}

function initializeApp(data) {
    document.getElementById('languagefield').textContent = data.language;
    document.getElementById('viewtypefield').textContent = data.context.viewType;
    document.getElementById('useridfield').textContent = data.context.userId;
    document.getElementById('utouidfield').textContent = data.context.utouId;
    document.getElementById('roomidfield').textContent = data.context.roomId;
    document.getElementById('groupidfield').textContent = data.context.groupId;
}
```

3\. push the change.

```
git commit -am "add profile"
git push origin master
```

4\. As LIFF application address didn't change at all, simply reopen the page to confirm the behavior.

<img src="https://qiita-image-store.s3.amazonaws.com/0/214116/e0c6842e-e492-3119-9921-23a6afb300d9.png" width="300"/>

### Send message from LIFF 

You can send messages to LINE bot from LIFF application. This is great feature to integrate the page into bot.

See detail at [liff.sendMessages()](https://developers.line.me/en/reference/liff/#liffsendmessages()) 

1\. Replcae the code for index.html

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My First LIFF</title>
</head>
<body>   
    <button id="sendmessagebutton">Send Message</button>
    <div id="profileinfo">
        <h2>Profile</h2>
        <div id="profilepicturediv">
        </div>
        <table border="1">
            <tr>
                <th>userId</th>
                <td id="useridprofilefield"></td>
            </tr>
            <tr>
                <th>displayName</th>
                <td id="displaynamefield"></td>
            </tr>
            <tr>
                <th>statusMessage</th>
                <td id="statusmessagefield"></td>
            </tr>
        </table>
    </div>

    <div id="liffdata">
        <h2>LIFF Data</h2>
        <table border="1">
            <tr>
                <th>language</th>
                <td id="languagefield"></td>
            </tr>
            <tr>
                <th>context.viewType</th>
                <td id="viewtypefield"></td>
            </tr>
            <tr>
                <th>context.userId</th>
                <td id="useridfield"></td>
            </tr>
            <tr>
                <th>context.utouId</th>
                <td id="utouidfield"></td>
            </tr>
            <tr>
                <th>context.roomId</th>
                <td id="roomidfield"></td>
            </tr>
            <tr>
                <th>context.groupId</th>
                <td id="groupidfield"></td>
            </tr>
        </table>
    </div>
    
    <!-- Load LIFF SDK -->
    <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
    <script src="liff.js"></script>
</body>
</html>
```

2\. Replace code of liff.js

```javascript
window.onload = function (e) {
    // initialize and get basic information
    // https://developers.line.me/en/reference/liff/#initialize-liff-app
    liff.init(function (data) {
        getProfile();
        initializeApp(data);
    });

    // Send message
    document.getElementById('sendmessagebutton').addEventListener('click', function () {
        // https://developers.line.me/en/reference/liff/#liffsendmessages()
        liff.sendMessages([{
            type: 'text',
            text: "Send text message"
        }, {
            type: 'sticker',
            packageId: '2',
            stickerId: '144'
        }]).then(function () {
            window.alert("Sent");
        }).catch(function (error) {
            window.alert("Error sending message: " + error);
        });
    });
};

// Get profile and display
function getProfile(){
    // https://developers.line.me/en/reference/liff/#liffgetprofile()
    liff.getProfile().then(function (profile) {
        document.getElementById('useridprofilefield').textContent = profile.userId;
        document.getElementById('displaynamefield').textContent = profile.displayName;

        var profilePictureDiv = document.getElementById('profilepicturediv');
        if (profilePictureDiv.firstElementChild) {
            profilePictureDiv.removeChild(profilePictureDiv.firstElementChild);
        }
        var img = document.createElement('img');
        img.src = profile.pictureUrl;
        img.alt = "Profile Picture";
        img.width = 200;
        profilePictureDiv.appendChild(img);

        document.getElementById('statusmessagefield').textContent = profile.statusMessage;
    }).catch(function (error) {
        window.alert("Error getting profile: " + error);
    });
}

function initializeApp(data) {
    document.getElementById('languagefield').textContent = data.language;
    document.getElementById('viewtypefield').textContent = data.context.viewType;
    document.getElementById('useridfield').textContent = data.context.userId;
    document.getElementById('utouidfield').textContent = data.context.utouId;
    document.getElementById('roomidfield').textContent = data.context.roomId;
    document.getElementById('groupidfield').textContent = data.context.groupId;
}
```

3\. Push again.

```
git commit -am "add send message"
git push origin master
```

4\. Use same LIFF address to confirm the behavior.

<img src="https://qiita-image-store.s3.amazonaws.com/0/214116/39f5d489-9d11-47d5-2659-60eab4aae102.png" width="300"/>

<img src="https://qiita-image-store.s3.amazonaws.com/0/214116/01f3b06f-c013-3755-3653-5205547c1ad4.png" width="300"/>

<img src="https://qiita-image-store.s3.amazonaws.com/0/214116/66f8228b-69ce-a59c-585c-0f94d216f931.png" width="300"/>


### Open new window from LIFF

You can open URL inside LINE or outside of LINE from LIFF.

1\. Replace code of index.html.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My First LIFF</title>
</head>
<body>   
    <button id="openwindowbutton">Open the window in LINE</button>
    <button id="openwindowexternalbutton">Open the window outside of LINE</button>
    <button id="sendmessagebutton">Send Message</button>
    <div id="profileinfo">
        <h2>Profile</h2>
        <div id="profilepicturediv">
        </div>
        <table border="1">
            <tr>
                <th>userId</th>
                <td id="useridprofilefield"></td>
            </tr>
            <tr>
                <th>displayName</th>
                <td id="displaynamefield"></td>
            </tr>
            <tr>
                <th>statusMessage</th>
                <td id="statusmessagefield"></td>
            </tr>
        </table>
    </div>

    <div id="liffdata">
        <h2>LIFF Data</h2>
        <table border="1">
            <tr>
                <th>language</th>
                <td id="languagefield"></td>
            </tr>
            <tr>
                <th>context.viewType</th>
                <td id="viewtypefield"></td>
            </tr>
            <tr>
                <th>context.userId</th>
                <td id="useridfield"></td>
            </tr>
            <tr>
                <th>context.utouId</th>
                <td id="utouidfield"></td>
            </tr>
            <tr>
                <th>context.roomId</th>
                <td id="roomidfield"></td>
            </tr>
            <tr>
                <th>context.groupId</th>
                <td id="groupidfield"></td>
            </tr>
        </table>
    </div>
    
    <!-- Load LIFF SDK -->
    <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
    <script src="liff.js"></script>
</body>
</html>
```

2\. Replace code of liff.js

```javascript
window.onload = function (e) {
    // initialize and get basic information
    // https://developers.line.me/en/reference/liff/#initialize-liff-app
    liff.init(function (data) {
        getProfile();
        initializeApp(data);
    });

    // Open window
    // https://developers.line.me/en/reference/liff/#liffopenwindow()
    document.getElementById('openwindowbutton').addEventListener('click', function () {
        liff.openWindow({
            url: 'https://line.me'
        });
    });

    document.getElementById('openwindowexternalbutton').addEventListener('click', function () {
        liff.openWindow({
            url: 'https://line.me',
            external: true
        });
    });

    // Send message
    document.getElementById('sendmessagebutton').addEventListener('click', function () {
        // https://developers.line.me/en/reference/liff/#liffsendmessages()
        liff.sendMessages([{
            type: 'text',
            text: "Send text message"
        }, {
            type: 'sticker',
            packageId: '2',
            stickerId: '144'
        }]).then(function () {
            window.alert("Sent");
        }).catch(function (error) {
            window.alert("Error sending message: " + error);
        });
    });
};

// Get profile and display
function getProfile(){
    // https://developers.line.me/en/reference/liff/#liffgetprofile()
    liff.getProfile().then(function (profile) {
        document.getElementById('useridprofilefield').textContent = profile.userId;
        document.getElementById('displaynamefield').textContent = profile.displayName;

        var profilePictureDiv = document.getElementById('profilepicturediv');
        if (profilePictureDiv.firstElementChild) {
            profilePictureDiv.removeChild(profilePictureDiv.firstElementChild);
        }
        var img = document.createElement('img');
        img.src = profile.pictureUrl;
        img.alt = "Profile Picture";
        img.width = 200;
        profilePictureDiv.appendChild(img);

        document.getElementById('statusmessagefield').textContent = profile.statusMessage;
    }).catch(function (error) {
        window.alert("Error getting profile: " + error);
    });
}

function initializeApp(data) {
    document.getElementById('languagefield').textContent = data.language;
    document.getElementById('viewtypefield').textContent = data.context.viewType;
    document.getElementById('useridfield').textContent = data.context.userId;
    document.getElementById('utouidfield').textContent = data.context.utouId;
    document.getElementById('roomidfield').textContent = data.context.roomId;
    document.getElementById('groupidfield').textContent = data.context.groupId;
}
```

3\. Push again.

```
git commit -am "add openwindow"
git push origin master
```

4\. Use same LIFF URL to confirm the behavior.

### Close LIFF application

User can close the LIFF by clicking [x] button or tap outside of LIFF area, but you can also close it by using SDK.

1\. Replace code of index.html.

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>My First LIFF</title>
</head>
<body>           
    <button id="closewindowbutton">Close LIFF application</button>
    <button id="openwindowbutton">Open the window in LINE</button>
    <button id="openwindowexternalbutton">Open the window outside of LINE</button>
    <button id="sendmessagebutton">Send Message</button>
    <div id="profileinfo">
        <h2>Profile</h2>
        <div id="profilepicturediv">
        </div>
        <table border="1">
            <tr>
                <th>userId</th>
                <td id="useridprofilefield"></td>
            </tr>
            <tr>
                <th>displayName</th>
                <td id="displaynamefield"></td>
            </tr>
            <tr>
                <th>statusMessage</th>
                <td id="statusmessagefield"></td>
            </tr>
        </table>
    </div>

    <div id="liffdata">
        <h2>LIFF Data</h2>
        <table border="1">
            <tr>
                <th>language</th>
                <td id="languagefield"></td>
            </tr>
            <tr>
                <th>context.viewType</th>
                <td id="viewtypefield"></td>
            </tr>
            <tr>
                <th>context.userId</th>
                <td id="useridfield"></td>
            </tr>
            <tr>
                <th>context.utouId</th>
                <td id="utouidfield"></td>
            </tr>
            <tr>
                <th>context.roomId</th>
                <td id="roomidfield"></td>
            </tr>
            <tr>
                <th>context.groupId</th>
                <td id="groupidfield"></td>
            </tr>
        </table>
    </div>
    
    <!-- Load LIFF SDK -->
    <script src="https://d.line-scdn.net/liff/1.0/sdk.js"></script>
    <script src="liff.js"></script>
</body>
</html>
```

2\. Replace code of liff.js.

```javascript
window.onload = function (e) {
    // initialize and get basic information
    // https://developers.line.me/en/reference/liff/#initialize-liff-app
    liff.init(function (data) {
        getProfile();
        initializeApp(data);
    });

    // Close LIFF application
    // https://developers.line.me/en/reference/liff/#liffclosewindow()
    document.getElementById('closewindowbutton').addEventListener('click', function () {
        liff.closeWindow();
    });

    // Open window
    // https://developers.line.me/en/reference/liff/#liffopenwindow()
    document.getElementById('openwindowbutton').addEventListener('click', function () {
        liff.openWindow({
            url: 'https://line.me'
        });
    });

    document.getElementById('openwindowexternalbutton').addEventListener('click', function () {
        liff.openWindow({
            url: 'https://line.me',
            external: true
        });
    });

    // Send message
    document.getElementById('sendmessagebutton').addEventListener('click', function () {
        // https://developers.line.me/en/reference/liff/#liffsendmessages()
        liff.sendMessages([{
            type: 'text',
            text: "Send text message"
        }, {
            type: 'sticker',
            packageId: '2',
            stickerId: '144'
        }]).then(function () {
            window.alert("Sent");
        }).catch(function (error) {
            window.alert("Error sending message: " + error);
        });
    });
};

// Get profile and display
function getProfile(){
    // https://developers.line.me/en/reference/liff/#liffgetprofile()
    liff.getProfile().then(function (profile) {
        document.getElementById('useridprofilefield').textContent = profile.userId;
        document.getElementById('displaynamefield').textContent = profile.displayName;

        var profilePictureDiv = document.getElementById('profilepicturediv');
        if (profilePictureDiv.firstElementChild) {
            profilePictureDiv.removeChild(profilePictureDiv.firstElementChild);
        }
        var img = document.createElement('img');
        img.src = profile.pictureUrl;
        img.alt = "Profile Picture";
        img.width = 200;
        profilePictureDiv.appendChild(img);

        document.getElementById('statusmessagefield').textContent = profile.statusMessage;
    }).catch(function (error) {
        window.alert("Error getting profile: " + error);
    });
}

function initializeApp(data) {
    document.getElementById('languagefield').textContent = data.language;
    document.getElementById('viewtypefield').textContent = data.context.viewType;
    document.getElementById('useridfield').textContent = data.context.userId;
    document.getElementById('utouidfield').textContent = data.context.utouId;
    document.getElementById('roomidfield').textContent = data.context.roomId;
    document.getElementById('groupidfield').textContent = data.context.groupId;
}
```

3\. Push.

```
git commit -am "add closewindow"
git push origin master
```

4\. Confirm the behavior.

### Update or Delete LIFF application

You can update registered LIFF application by using LIFF CLI or you can delete them.

Update

```
liff update <liffId> <url> <type:full|tall|compact>
```

Delete

```
liff delete <liffId>
liff deleteAll
```

Enjoy LIFF!