# Developing a LIFF app

This page explains the process of developing a LIFF app. After developing the LIFF app, deploy it on any server.

# Developing a LIFF app

A LIFF app is a web app based on HTML and JavaScript. Here, we'll explain processes specific to building LIFF apps.

# Setting the title of the LIFF app

The title of the LIFF app will appear in the title bar of the LIFF app. Specify the name of the LIFF app in the <title> element of the HTML source of the web app.

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>LIFF Starter</title>
        <link rel="stylesheet" href="style.css">

# Integrating the LIFF SDK with the LIFF app

You can embed the LIFF SDK in the LIFF app using these methods:

# Specify the CDN path

To use the functions of the LIFF SDK, specify the URL of the LIFF SDK in the src attribute of the <script> element of the LIFF app's HTML source. We prepare these two types of CDN paths. Specify the CDN path that suits your purpose.

CDN path Description
CDN edge path This is a CDN path that contains only the MAJOR version. Use this CDN path if you want to always be up-to-date with the latest LIFF features. You only need to update your URL when a new MAJOR version is released.
e.g.: https://static.line-scdn.net/liff/edge/2/sdk.js
CDN fixed path This is a CDN path that contains up to the PATCH version. Use this CDN path if you want to use the LIFF features of a specific version. You can continue to use the specified PATCH version as long as you don't update the LIFF app. Update your URL only when you want to implement our new features, security updates, and bug fixes. It's not updated automatically and isn't affected by the LIFF SDK update.
e.g.: https://static.line-scdn.net/liff/edge/versions/2.1.13/sdk.js
Which version should you use?

Developers using the CDN fixed path will need to decide when to update their LIFF app. You can evaluate each update we provide by frequently checking the Release notes in the LIFF documentation and decide if the update is right for you.

Example of specifying a CDN edge path:

<script charset="utf-8" src="https://static.line-scdn.net/liff/edge/2/sdk.js"></script>
LIFF SDK is written in UTF-8

The LIFF SDK is written in UTF-8, so if your HTML source uses a character encoding different than UTF-8, make sure you also specify charset="utf-8".

# Use the npm package

The LIFF SDK is available as an npm package. You can use npm to install the LIFF SDK.

Manage your SDK version

It is the developer's responsibility to use an appropriate SDK version. To keep your SDK version up to date, check the LIFF release notes on a regular basis, and update your local SDK frequently. For more information about LIFF's versioning policy, see LIFF SDK (sdk.js) update policy.

npm package trial

The npm package is available on a trial basis. It may be changed or deleted in the future without notice.

To install the LIFF SDK via npm and import it into your app, follow these steps:

  1. Run this command in your terminal to install the LIFF SDK via npm:

    $ npm install --save @line/liff
    

    Alternatively, you can run this command in your terminal to install the LIFF SDK via Yarn:

    $ yarn add @line/liff
    
  2. Import the SDK into your app

    Include the following code in your JavaScript or TypeScript file:

    import liff from '@line/liff';
    
    liff.init({ liffId: 'myLiffId' });
    

    Type definitions for TypeScript are already included in the @line/liff package.

    Do not delcare or modify window.liff

    For backward compatibility, please do not declare or modify the global LIFF instance window.liff. Declaring or modifying window.liff may cause malfunctioning of the LINE app.

Related page: https://www.npmjs.com/package/@line/liff (opens new window)

# Calling the LIFF API

You can do these things after integrating the LIFF SDK.

# Initializing the LIFF app

Note the timing when you call liff.init() method

When users are first redirected to the endpoint URL (primary redirect URL), execute the liff.init() method. If executing the liff.init() method, except for the above timing, INIT_FAILED is returned and the LIFF app can't be opened. For more information, see Behaviors from accessing the LIFF URL to opening the LIFF app.

The liff.init() method initializes the LIFF app and enables you to call the other methods of the LIFF SDK from the LIFF app.

Functions that can be executed even before the LIFF app is initialized

This property or methods are available even before the liff.init() method is executed.

You can get the environment in which the LIFF app is running before initializing the LIFF app, or close the LIFF app when the LIFF app initialization fails.

To use the liff.closeWindow() method before the initialization of the LIFF app by liff.init() has finished, your LIFF SDK version must be v2.4.0 or later, and the user's LINE version must be 10.15.0 or later.

liffId needs a specified LIFF app ID, which you can get by adding the LIFF app to your channel. For more information, see Adding a LIFF app to your channel.

/**
* Initialize LIFF
* @param {string} myLiffId The LIFF app ID of the selected element
*/
function initializeLiff(myLiffId) {
    liff
        .init({
            liffId: myLiffId
        })
        .then(() => {
            // start to use LIFF's api
            initializeApp();
        })
        .catch((err) => {
            document.getElementById("liffAppContent").classList.add('hidden');
            document.getElementById("liffInitErrorMessage").classList.remove('hidden');
        });
}

Also, with liff.ready, you can get the Promise object that resolves when you run liff.init() for the first time after starting the LIFF app.

For more information, see the liff.init() and liff.ready sections in the LIFF v2 API reference.

# To use LINE Login in an external browser

To use LINE Login in an external browser, call the liff.init() method twice as shown below.

  1. Call the liff.init() method after loading the LIFF SDK.

  2. Call the liff.login() method. Once the processing of the authentication page and the authorization screen is complete, you will be redirected to the LIFF app (redirectUri). Call the liff.init() method again.

    If an error occurs during the processing of the liff.init() method, or if the user cancels authorization at the time of login, errorCallback will be executed.

Flow diagram

# Getting the environment in which the LIFF app is running

Call the liff.isInClient() method and the liff.getOS() method to get the environment in which the LIFF app is running.

/**
* Display data generated by invoking LIFF methods
*/
function displayLiffData() {
    document.getElementById('browserLanguage').textContent = liff.getLanguage();
    document.getElementById('sdkVersion').textContent = liff.getVersion();
    document.getElementById('isInClient').textContent = liff.isInClient();
    document.getElementById('isLoggedIn').textContent = liff.isLoggedIn();
    document.getElementById('deviceOS').textContent = liff.getOS();
    document.getElementById('lineVersion').textContent = liff.getLineVersion();
}

For more information, see liff.getOS() and liff.isInClient() in the LIFF v2 API reference.

# Performing login with LINE Login

Call the liff.login() method to perform the LINE Login process for both the LINE's in-app browser and external browsers.

Note

You can't use liff.login() in a LIFF browser, as it's automatically executed when liff.init() is executed.

// login call, only when external browser or LINE's in-app browser is used
document.getElementById('liffLoginButton').addEventListener('click', function() {
    if (!liff.isLoggedIn()) {
        liff.login();
    }
});

You can also call the liff.logout() method to log out.

// logout call only when external browse
document.getElementById('liffLogoutButton').addEventListener('click', function() {
    if (liff.isLoggedIn()) {
        liff.logout();
        window.location.reload();
    }
});

For more information, see liff.login() and liff.logout() in the LIFF v2 API reference.

# URL validation

If redirectUri is specified in the liff.login() argument, it verifies that the endpoint URL set to the channel of the accessed LIFF URL matches the URL specified in redirectUri.

if (!liff.isLoggedIn()) {
  liff.login({ redirectUri: "https://example.com/path" });
  // Verify that the domain name and path (https://example.com/path) match the endpoint URL.
}

If the URL doesn't match, an error message will be displayed and LINE Login will fail.

Error screen when liff init fails

The criteria for URL matching will differ depending on the Method for converting additional information in the LIFF URL setting.

  • When "Method for converting additional information in the LIFF URL" is set to "Concatenate":

If the domain name and path (https://example.com/path) are included, the login process will succeed.

  • When "Method for converting additional information in the LIFF URL" is set to "Replace (Backward compatibility mode)":

If the domain name (https://example.com) is included, the login process will succeed.

For example, if the Endpoint URL is https://example.com/path1/path2?k=v, the URL match will be as follows.

Method for converting additional information in the LIFF URL redirectUri Login process
Concatenate
  • https://example.com/path1/path2?k=v
  • https://example.com/path1/path2
  • https://example.com/path1/path2/
  • https://example.com/path1/path2/path3
✅ Success
  • https://example.com/path1
  • https://example.com/
  • https://example.com/path2/path1
❌ Failure
Replace (Backward compatibility mode)
  • https://example.com/path1/path2?k=v
  • https://example.com/path1/path2
  • https://example.com/path1/path2/path3
  • https://example.com/path1
  • https://example.com/
  • https://example.com/path4/path5
✅ Success

# Opening a URL

The liff.openWindow() method opens the specified URL in LINE's in-app browser or an external browser.

The following code opens https://line.me in an external browser.

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

For more information, see liff.openWindow() in the LIFF API reference.

To open a PDF

In the HTML source of the web app, in the <a href=""> attribute, specify the path of the target PDF:

<a href="/path/to/your.pdf">Open a PDF</a>

Clicking this link opens the PDF in LINE's in-app browser or an external browser.

To make the PDF open in a new tab, add target="_blank":

<a href="/path/to/your.pdf" target="_blank">Open a PDF in another tab</a>

# Opening the QR code reader

Call the liff.scanCode() method to start LINE's QR code reader, and get the string read by the user.

// scanCode call
document.getElementById('scanQrCodeButton').addEventListener('click', function() {
    if (!liff.isInClient()) {
        sendAlertIfNotInClient();
    } else {
    	if (liff.scanCode) {
	        liff.scanCode().then(result => {
	            // e.g. result = { value: "Hello LIFF app!" }
	            const stringifiedResult = JSON.stringify(result);
	            document.getElementById('scanQrField').textContent = stringifiedResult;
	            toggleQrCodeReader();
	        }).catch(err => {
	            document.getElementById('scanQrField').textContent = "scanCode failed!";
	        });
    	}
    }
});

For more information, see liff.scanCode() in the LIFF v2 API reference.

Not available on LINE 9.19.0 or later for iOS

Due to a technical issue, liff.scanCode() will be undefined on LINE 9.19.0 or later for iOS. Check the existence of the function as shown in the sample code before using it.

Note

You cannot use liff.scanCode() in an external browser.

# Getting the screen type from which the LIFF app was launched

Execute the liff.getContext() method to get a value that specifies the screen type (1-on-1 chat, group, room, or external browser) from which the LIFF app is launched. For 1-on-1 chats, groups, and rooms, you also get a unique ID.

const context = liff.getContext();
console.log(context);
// {"type": "utou", "utouId": "UU29e6eb36812f484fd275d41b5af4e760926c516d8c9faa35…b1e8de8fbb6ecb263ee8724e48118565e3368d39778fe648d", "userId": "U70e153189a29f1188b045366285346bc", "viewType": "full", "accessTokenHash": "ArIXhlwQMAZyW7SDHm7L2g", "availability": {"shareTargetPicker": {"permission": true, "minVer": "10.3.0"}, "multipleLiffTransition": {"permission": true, "minVer": "10.18.0"}}}

For more information, see liff.getContext() in the LIFF v2 API reference.

# Get user profile

There are two ways to get a user's profile in the LIFF app.

Use the method for your intended purpose.

# Send user information to the server

When the LIFF app sends user information to the server, it sends the access token or ID token obtained via this method. For more information, see Using user information in LIFF apps and servers in the LIFF documentation.

  • Execute the liff.getAccessToken() method to get the access token of the current user.

    // get access token
    document.getElementById('getAccessToken').addEventListener('click', function() {
        if (!liff.isLoggedIn() && !liff.isInClient()) {
            alert('To get an access token, you need to be logged in. Please tap the "login" button below and try again.');
        } else {
            const accessToken = liff.getAccessToken();
            document.getElementById('accessTokenField').textContent = accessToken;
            toggleAccessToken();
        }
    });
    

    For more information, see liff.getAccessToken() in the LIFF v2 API reference.

  • Execute the liff.getIDToken() method to get the raw ID token of the current user.

    liff.init(() => {
        const idToken = liff.getIDToken();
        console.log(idToken) // print raw idToken object
    });
    

    For more information, see liff.getIDToken() in the LIFF v2 API reference.

# Display user information to the LIFF app

Execute the liff.getDecodedIDToken() method to get the profile information and email address of the current user.

Use this API to use the user's display name in the LIFF app.

Don't send user information to the server

Don't send the user information obtained by liff.getDecodedIDToken() to the server. Send the ID token obtained with liff.getIDToken() instead.

liff.init(() => {
    const idToken = liff.getDecodedIDToken();
    console.log(idToken) // print decoded idToken object
});

For more information, see liff.getDecodedIDToken() in the LIFF v2 API reference.

# Getting the friendship status between the user and the LINE Official Account

Gets the friendship status between the user and the LINE Official Account that's linked to the LINE Login channel to which the LIFF app is added.

Learn more on how to Add a LINE Official Account as a friend when logged in (bot link) in the LINE Login documentation.

liff.getFriendship().then(data => {
  if (data.friendFlag) {
    // something you want to do
  }
)

Learn more from liff.getFriendship() in the LIFF v2 API reference.

The LIFF SDK keeps a permanent link for the current page.

Execute the liff.permanentLink.createUrl() method to get the permanent link.

// For example, if current location is
// /shopping?item_id=99#details
// (LIFF ID = 1234567890-AbcdEfgh)
const myLink = liff.permanentLink.createUrl()

// myLink equals "https://liff.line.me/1234567890-AbcdEfgh/shopping?item_id=99#details"

For more information, see liff.permanentLink.createUrl() in the LIFF v2 API reference.

In addition, you can add query parameters to the permanent links on the current page.

// For example, if current location is
// /food?menu=pizza
// (LIFF ID = 1234567890-AbcdEfgh)
liff.permanentLink.setExtraQueryParam('user_tracking_id=8888')
const myLink = liff.permanentLink.createUrl()


// myLink equals "https://liff.line.me/1234567890-AbcdEfgh/food?menu=pizza&user_tracking_id=8888"

For more information, see liff.permanentLink.setExtraQueryParam() in the LIFF v2 API reference.

# Sending messages to the current chat screen

The liff.sendMessages() method sends messages on behalf of the user to the chat screen where the LIFF app is opened. You can send up to 5 message objects in a single request. If you open the LIFF app in any screen other than the chat screen, you will not be able to send messages.

The following code sends "Hello, World!" as the user's message to the chat screen where the LIFF app is displayed.

// sendMessages call
document.getElementById('sendMessageButton').addEventListener('click', function() {
    if (!liff.isInClient()) {
        sendAlertIfNotInClient();
    } else {
        liff.sendMessages([{
            'type': 'text',
            'text': "You've successfully sent a message! Hooray!"
        }]).then(function() {
            window.alert('Message sent');
        }).catch(function(error) {
            window.alert('Error sending message: ' + error);
        });
    }
});

For more information, see liff.sendMessages() in the LIFF v2 API reference.

Note

You cannot use liff.sendMessages() in an external browser.

# Sending messages to a user's friend (share target picker)

Execute the liff.shareTargetPicker() method to display the target picker (screen for selecting a group or friend) and send the message created by the developer to the selected target. This message appears to your group or friends as if you had sent it.

target picker

The following code displays the target picker and sends "Hello, World!" as the user's message to the selected group or friends. If you want to confirm that the target picker can be used in the environment where the LIFF app is started, execute liff.isApiAvailable() first.

if (liff.isApiAvailable('shareTargetPicker')) {
  liff.shareTargetPicker([
    {
      type: "text",
      text: "Hello, World!"
    }
  ])
}

For more information, see liff.isApiAvailable() and liff.shareTargetPicker() in the LIFF v2 API reference.

Note
  • To view the target picker, turn on the share target picker in the LINE Developers Console. For more information, see Using share target picker.
  • When using an external browser, call liff.login(), complete the LINE Login process (web login), then call liff.shareTargetPicker().
Target picker operating environment

Target picker is supported on 10.3.0 or later for both LINE for iOS and LINE for Android.

When you launch the target picker on earlier versions, you will get an error message. Before executing liff.shareTargetPicker(), you can confirm that the target picker is available in the environment where the LIFF app is started by executing liff.isApiAvailable().

# Closing the LIFF app

The liff.closeWindow() method closes the opened LIFF app.

// closeWindow call
document.getElementById('closeWindowButton').addEventListener('click', function() {
    if (!liff.isInClient()) {
        sendAlertIfNotInClient();
    } else {
        liff.closeWindow();
    }
});

For more information, see liff.closeWindow() in the LIFF v2 API reference.

Note

You cannot use liff.closeWindow() in an external browser.

# Setting the OGP tags

By setting an OGP tag for each page of the LIFF app, for example, you can display any title, description, or thumbnail image when sharing the URL of your LIFF app (https://liff.line.me/{liffId}) in the LINE talk room, and so on.

These are the OGP tags supported by LIFF. For more information on OGP tags, see The Open Graph protocol (opens new window).

<html lang="ja" prefix="og: http://ogp.me/ns#">
<meta property="og:title" content="The title">
<meta property="og:type" content="`website`, `blog`, or `article`">
<meta property="og:description" content="A one to two sentence description">
<meta property="og:url" content="The URL">
<meta property="og:site_name" content="The name that represents the overall site">
<meta property="og:image" content="An image URL">
Note

When sharing the URL of the LIFF app in the format of line://app/{liffId} (deprecated), the OGP tag will be ignored.

# Next steps

After deploying the LIFF app on any server, do these things:

  1. Add the LIFF app to your channel.
  2. Open the LIFF app