[{"data":1,"prerenderedAt":795},["ShallowReactive",2],{"h2442249291":3,"h2793278848":489,"h2288135819":785},{"id":4,"title":5,"body":6,"description":479,"extension":480,"meta":481,"navigation":484,"path":485,"seo":486,"stem":487,"__hash__":488},"docs\u002Fen\u002Ftips\u002F2026\u002F07\u002F30\u002Fliff-ready.md","liff.ready lets you wait for liff.init() completion from anywhere, with one caveat",{"type":7,"value":8,"toc":462},"minimark",[9],[10,11,12,20,25,38,47,70,81,90,108,152,226,246,252,258,274,300,328,331,378,393,397,414,418,447,453,457],"Tips",{},[13,14,17],"h1",{"id":15,"class":16},"","!mb-4",[18,19],"page-title",{},[21,22],"display-date",{"date":23,"class":24},"2026\u002F07\u002F30","!mb-20",[26,27,28,29,37],"p",{},"In this article, we'll introduce ",[30,31,33],"a",{"href":32},"\u002Freference\u002Fliff\u002F#ready",[34,35,36],"code",{},"liff.ready",", a modest but handy property, and a caveat you should know about when using it.",[39,40,42,43,46],"h2",{"id":41},"where-to-await-init","Where to wait for ",[34,44,45],{},"liff.init()"," to complete",[26,48,49,50,56,57,62,63,66,67,69],{},"In a LIFF app, many methods, such as the ",[30,51,53],{"href":52},"\u002Freference\u002Fliff\u002F#get-profile",[34,54,55],{},"liff.getProfile()"," method, can only be called after the ",[30,58,60],{"href":59},"\u002Freference\u002Fliff\u002F#initialize-liff-app",[34,61,45],{}," method has finished. While your app is small, you can simply write all your logic inside ",[34,64,65],{},"liff.init().then(...)",". However, as your code gets split into modules and files, you'll want to guarantee that ",[34,68,45],{}," has finished in event handlers and utility functions as well.",[26,71,72,73,75,76,80],{},"You can build such a mechanism yourself. For example, you can export and share the Promise returned by ",[34,74,45],{},", or manage your own flag that indicates whether initialization has finished. That said, the LIFF SDK also comes with a built-in property for this purpose: ",[30,77,78],{"href":32},[34,79,36],{},".",[39,82,84,85,87,88,15],{"id":83},"decouple-with-liff-ready","Separate where you call ",[34,86,45],{}," from where you wait with ",[34,89,36],{},[26,91,92,94,95,97,98,100,101,103,104,107],{},[34,93,36],{}," is a property holding a Promise that resolves when ",[34,96,45],{}," succeeds. Since you can reference it even before calling ",[34,99,45],{},", you can call ",[34,102,45],{}," only once at the entry point of your app, and ",[34,105,106],{},"await liff.ready"," wherever you want to wait for its completion.",[109,110,114],"pre",{"className":111,"code":112,"language":113,"meta":15,"style":15},"language-javascript shiki shiki-themes github-dark-default","\u002F\u002F Entry point: call liff.init() only once here, and handle errors here too\nliff.init({ liffId: 'YOUR-LIFF-ID' }).catch(handleInitError);\n","javascript",[34,115,116,125],{"__ignoreMap":15},[117,118,121],"span",{"class":119,"line":120},"line",1,[117,122,124],{"class":123},"sH3jZ","\u002F\u002F Entry point: call liff.init() only once here, and handle errors here too\n",[117,126,128,132,136,139,143,146,149],{"class":119,"line":127},2,[117,129,131],{"class":130},"sZEs4","liff.",[117,133,135],{"class":134},"sc3cj","init",[117,137,138],{"class":130},"({ liffId: ",[117,140,142],{"class":141},"s9uIt","'YOUR-LIFF-ID'",[117,144,145],{"class":130}," }).",[117,147,148],{"class":134},"catch",[117,150,151],{"class":130},"(handleInitError);\n",[109,153,155],{"className":111,"code":154,"language":113,"meta":15,"style":15},"\u002F\u002F Click handler or utility function: only wait for liff.init() to complete\nasync function loadProfile() {\n  await liff.ready;\n  const profile = await liff.getProfile();\n  showDisplayName(profile.displayName);\n}\n",[34,156,157,162,177,186,211,220],{"__ignoreMap":15},[117,158,159],{"class":119,"line":120},[117,160,161],{"class":123},"\u002F\u002F Click handler or utility function: only wait for liff.init() to complete\n",[117,163,164,168,171,174],{"class":119,"line":127},[117,165,167],{"class":166},"suJrU","async",[117,169,170],{"class":166}," function",[117,172,173],{"class":134}," loadProfile",[117,175,176],{"class":130},"() {\n",[117,178,180,183],{"class":119,"line":179},3,[117,181,182],{"class":166},"  await",[117,184,185],{"class":130}," liff.ready;\n",[117,187,189,192,196,199,202,205,208],{"class":119,"line":188},4,[117,190,191],{"class":166},"  const",[117,193,195],{"class":194},"sFSAA"," profile",[117,197,198],{"class":166}," =",[117,200,201],{"class":166}," await",[117,203,204],{"class":130}," liff.",[117,206,207],{"class":134},"getProfile",[117,209,210],{"class":130},"();\n",[117,212,214,217],{"class":119,"line":213},5,[117,215,216],{"class":134},"  showDisplayName",[117,218,219],{"class":130},"(profile.displayName);\n",[117,221,223],{"class":119,"line":222},6,[117,224,225],{"class":130},"}\n",[26,227,228,229,231,232,235,236,239,240,242,243,245],{},"The advantage of ",[34,230,36],{}," is how effortless it is. You can wait for the completion directly on the imported ",[34,233,234],{},"liff"," object, without wiring up your own Promise or flag. Even if ",[34,237,238],{},"loadProfile()"," is called before ",[34,241,45],{}," has finished, the subsequent processing runs after ",[34,244,36],{}," is resolved.",[39,247,249,251],{"id":248},"liff-ready-never-rejects",[34,250,36],{}," only tells you about success",[26,253,254,255,257],{},"Now for the main topic. The ",[30,256,36],{"href":32}," section of the LIFF API reference says the following:",[259,260,261],"blockquote",{},[26,262,263,264,266,267,269,270,273],{},"If ",[34,265,45],{}," fails, ",[34,268,36],{}," will not be rejected. Also, it doesn't return a ",[34,271,272],{},"LiffError"," object.",[26,275,276,277,279,280,282,283,287,288,290,291,293,294,296,297,299],{},"In other words, if ",[34,278,45],{}," fails due to a misconfigured LIFF ID or a network error, ",[34,281,36],{}," isn't rejected. Instead, ",[284,285,286],"strong",{},"it remains unresolved forever",". In the earlier ",[34,289,238],{}," example, execution never gets past ",[34,292,106],{},". Since no error is delivered to the ",[34,295,36],{}," side, if you expect error handling from ",[34,298,36],{},", you'll end up in a hard-to-diagnose situation where nothing is rendered on the screen, but there is no relevant error in the console either.",[26,301,302,304,305,307,308,310,311,314,315,317,318,320,321,324,325,327],{},[34,303,36],{}," is a simple completion signal that only tells you whether ",[34,306,45],{}," has finished, and it isn't responsible for error handling. Handle errors on the Promise returned by ",[34,309,45],{},". This is why the first code example attaches ",[34,312,313],{},".catch(handleInitError)"," to ",[34,316,45],{}," at the entry point. Initialization failures are delivered only to this ",[34,319,148],{},". If ",[34,322,323],{},"handleInitError"," switches to an error screen, for example, you can avoid leaving the user with a blank screen even while the code awaiting ",[34,326,36],{}," stays suspended.",[26,329,330],{},"The roles are divided as follows.",[332,333,334,347],"table",{},[335,336,337],"thead",{},[338,339,340,344],"tr",{},[341,342,343],"th",{},"What you want to do",[341,345,346],{},"What to use",[348,349,350,363],"tbody",{},[338,351,352,359],{},[353,354,355,356,358],"td",{},"Wait for ",[34,357,45],{}," to complete from anywhere",[353,360,361],{},[34,362,36],{},[338,364,365,370],{},[353,366,367,368],{},"Handle failures of ",[34,369,45],{},[353,371,372,373,375,376],{},"The ",[34,374,148],{}," of the Promise returned by ",[34,377,45],{},[26,379,380,381,383,384,386,387,389,390,392],{},"If you also want to know about failures where you wait for ",[34,382,45],{}," to complete, share and await the Promise returned by ",[34,385,45],{}," instead of ",[34,388,36],{},". That Promise is rejected on failure. You can also put the result of the initialization in your app's state management. For apps that need failure handling in many places, sharing the Promise from the start is a better fit. ",[34,391,36],{}," is a property for casually waiting only for success.",[39,394,396],{"id":395},"pluggable-sdk","You can also use it with the pluggable SDK",[26,398,399,400,404,405,409,410,413],{},"Since ",[30,401,402],{"href":32},[34,403,36],{}," is included in the core of the SDK, you can use it as is without any additional modules, even if you use the ",[30,406,408],{"href":407},"\u002Fdocs\u002Fliff\u002Fpluggable-sdk\u002F","pluggable SDK"," (",[34,411,412],{},"@line\u002Fliff\u002Fcore",") to reduce the bundle size.",[39,415,417],{"id":416},"wrap-up","Wrap-up",[419,420,421,431,441],"ul",{},[422,423,424,425,427,428,430],"li",{},"With ",[34,426,36],{},", you can easily wait for ",[34,429,45],{}," to complete without any wiring of your own.",[422,432,433,434,436,437,375,439,80],{},"However, ",[34,435,36],{}," doesn't notify you of failures. Handle errors with the ",[34,438,148],{},[34,440,45],{},[422,442,443,444,446],{},"If you also want to know about failures where you wait, consider sharing the Promise returned by ",[34,445,45],{}," or putting the result in your app's state management.",[26,448,449,450,452],{},"For more information, see ",[30,451,36],{"href":32}," in the LIFF API reference.",[454,455,456],"style",{},"html pre.shiki code .sH3jZ, html code.shiki .sH3jZ{--shiki-default:#8B949E}html pre.shiki code .sZEs4, html code.shiki .sZEs4{--shiki-default:#E6EDF3}html pre.shiki code .sc3cj, html code.shiki .sc3cj{--shiki-default:#D2A8FF}html pre.shiki code .s9uIt, html code.shiki .s9uIt{--shiki-default:#A5D6FF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .suJrU, html code.shiki .suJrU{--shiki-default:#FF7B72}html pre.shiki code .sFSAA, html code.shiki .sFSAA{--shiki-default:#79C0FF}",[458,459],"tags",{"tags":234,"lang":460,"section":461},"en","tips",{"title":15,"searchDepth":188,"depth":213,"links":463},[464,467,470,473,476],{"id":465,"depth":127,"text":466},"where-to-wait-for-liffinit-to-complete-where-to-await-init","Where to wait for liff.init() to complete {#where-to-await-init}",{"id":468,"depth":127,"text":469},"separate-where-you-call-liffinit-from-where-you-wait-with-liffready-decouple-with-liff-ready","Separate where you call liff.init() from where you wait with liff.ready {#decouple-with-liff-ready}",{"id":471,"depth":127,"text":472},"liffready-only-tells-you-about-success-liff-ready-never-rejects","liff.ready only tells you about success {#liff-ready-never-rejects}",{"id":474,"depth":127,"text":475},"you-can-also-use-it-with-the-pluggable-sdk-pluggable-sdk","You can also use it with the pluggable SDK {#pluggable-sdk}",{"id":477,"depth":127,"text":478},"wrap-up-wrap-up","Wrap-up {#wrap-up}","In this article, we'll introduce liff.ready, a modest but handy property, and a caveat you should know about when using it.","md",{"date":482,"tags":234,"locale":460,"sidebar":483},"2026-07-30 00:00 UTC",false,true,"\u002Fen\u002Ftips\u002F2026\u002F07\u002F30\u002Fliff-ready",{"title":5,"description":479},"en\u002Ftips\u002F2026\u002F07\u002F30\u002Fliff-ready","Xf8dHZHppP-h09YG63cOzuXCBn9xdnEQmYtRtKdr_hg",{"id":4,"title":5,"body":490,"description":479,"extension":480,"meta":783,"navigation":484,"path":485,"seo":784,"stem":487,"__hash__":488},{"type":7,"value":491,"toc":776},[492],[10,493,494,498,500,506,510,524,532,538,550,574,624,636,640,644,654,670,688,690,724,734,736,746,748,768,772,774],{},[13,495,496],{"id":15,"class":16},[18,497],{},[21,499],{"date":23,"class":24},[26,501,28,502,37],{},[30,503,504],{"href":32},[34,505,36],{},[39,507,42,508,46],{"id":41},[34,509,45],{},[26,511,49,512,56,516,62,520,66,522,69],{},[30,513,514],{"href":52},[34,515,55],{},[30,517,518],{"href":59},[34,519,45],{},[34,521,65],{},[34,523,45],{},[26,525,72,526,75,528,80],{},[34,527,45],{},[30,529,530],{"href":32},[34,531,36],{},[39,533,84,534,87,536,15],{"id":83},[34,535,45],{},[34,537,36],{},[26,539,540,94,542,97,544,100,546,103,548,107],{},[34,541,36],{},[34,543,45],{},[34,545,45],{},[34,547,45],{},[34,549,106],{},[109,551,552],{"className":111,"code":112,"language":113,"meta":15,"style":15},[34,553,554,558],{"__ignoreMap":15},[117,555,556],{"class":119,"line":120},[117,557,124],{"class":123},[117,559,560,562,564,566,568,570,572],{"class":119,"line":127},[117,561,131],{"class":130},[117,563,135],{"class":134},[117,565,138],{"class":130},[117,567,142],{"class":141},[117,569,145],{"class":130},[117,571,148],{"class":134},[117,573,151],{"class":130},[109,575,576],{"className":111,"code":154,"language":113,"meta":15,"style":15},[34,577,578,582,592,598,614,620],{"__ignoreMap":15},[117,579,580],{"class":119,"line":120},[117,581,161],{"class":123},[117,583,584,586,588,590],{"class":119,"line":127},[117,585,167],{"class":166},[117,587,170],{"class":166},[117,589,173],{"class":134},[117,591,176],{"class":130},[117,593,594,596],{"class":119,"line":179},[117,595,182],{"class":166},[117,597,185],{"class":130},[117,599,600,602,604,606,608,610,612],{"class":119,"line":188},[117,601,191],{"class":166},[117,603,195],{"class":194},[117,605,198],{"class":166},[117,607,201],{"class":166},[117,609,204],{"class":130},[117,611,207],{"class":134},[117,613,210],{"class":130},[117,615,616,618],{"class":119,"line":213},[117,617,216],{"class":134},[117,619,219],{"class":130},[117,621,622],{"class":119,"line":222},[117,623,225],{"class":130},[26,625,228,626,231,628,235,630,239,632,242,634,245],{},[34,627,36],{},[34,629,234],{},[34,631,238],{},[34,633,45],{},[34,635,36],{},[39,637,638,251],{"id":248},[34,639,36],{},[26,641,254,642,257],{},[30,643,36],{"href":32},[259,645,646],{},[26,647,263,648,266,650,269,652,273],{},[34,649,45],{},[34,651,36],{},[34,653,272],{},[26,655,276,656,279,658,282,660,287,662,290,664,293,666,296,668,299],{},[34,657,45],{},[34,659,36],{},[284,661,286],{},[34,663,238],{},[34,665,106],{},[34,667,36],{},[34,669,36],{},[26,671,672,304,674,307,676,310,678,314,680,317,682,320,684,324,686,327],{},[34,673,36],{},[34,675,45],{},[34,677,45],{},[34,679,313],{},[34,681,45],{},[34,683,148],{},[34,685,323],{},[34,687,36],{},[26,689,330],{},[332,691,692,700],{},[335,693,694],{},[338,695,696,698],{},[341,697,343],{},[341,699,346],{},[348,701,702,712],{},[338,703,704,708],{},[353,705,355,706,358],{},[34,707,45],{},[353,709,710],{},[34,711,36],{},[338,713,714,718],{},[353,715,367,716],{},[34,717,45],{},[353,719,372,720,375,722],{},[34,721,148],{},[34,723,45],{},[26,725,380,726,383,728,386,730,389,732,392],{},[34,727,45],{},[34,729,45],{},[34,731,36],{},[34,733,36],{},[39,735,396],{"id":395},[26,737,399,738,404,742,409,744,413],{},[30,739,740],{"href":32},[34,741,36],{},[30,743,408],{"href":407},[34,745,412],{},[39,747,417],{"id":416},[419,749,750,756,764],{},[422,751,424,752,427,754,430],{},[34,753,36],{},[34,755,45],{},[422,757,433,758,436,760,375,762,80],{},[34,759,36],{},[34,761,148],{},[34,763,45],{},[422,765,443,766,446],{},[34,767,45],{},[26,769,449,770,452],{},[30,771,36],{"href":32},[454,773,456],{},[458,775],{"tags":234,"lang":460,"section":461},{"title":15,"searchDepth":188,"depth":213,"links":777},[778,779,780,781,782],{"id":465,"depth":127,"text":466},{"id":468,"depth":127,"text":469},{"id":471,"depth":127,"text":472},{"id":474,"depth":127,"text":475},{"id":477,"depth":127,"text":478},{"date":482,"tags":234,"locale":460,"sidebar":483},{"title":5,"description":479},{"toc":786,"fullToc":786},[787,789,791,793,794],{"id":41,"depth":127,"text":788},"Where to wait for liff.init() to complete",{"id":83,"depth":127,"text":790},"Separate where you call liff.init() from where you wait with liff.ready",{"id":248,"depth":127,"text":792},"liff.ready only tells you about success",{"id":395,"depth":127,"text":396},{"id":416,"depth":127,"text":417},1786511926831]