Packages

Metaex is an Elixir library that streamlines interactions with Meta's APIs (Facebook, Instagram, WhatsApp). It simplifies API requests, authentication, and error handling, making it easy to integrate Meta services into your Elixir applications.

Current section

Files

Jump to
metaex lib instagram instagram.ex
Raw

lib/instagram/instagram.ex

defmodule Metaex.Instagram do
import Metaex.Auth
def user_info_url(access_token, ig_user_id),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{ig_user_id}")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
fields:
"biography,ig_id,followers_count,follows_count,media_count,name,profile_picture_url,username,website"
})
)
|> to_string
def user_insights_url(
access_token,
ig_user_id,
metric \\ "reach,impressions",
period \\ "days_28"
),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{ig_user_id}/insights")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
metric: metric,
period: period
})
)
|> to_string
def ig_user_tags_url(
access_token,
ig_user_id
),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{ig_user_id}/tags")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
fields:
"id,username,thumbnail_url,media_url,media_type,media_product_type,like_count,ig_id,comments_count,caption"
})
)
|> to_string
def business_info_url(access_token, page_id),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{page_id}")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
fields:
"instagram_business_account,link,name,username,website,general_info,followers_count,description,cover,category,id"
})
)
|> to_string
@doc """
Returns a list of Media IDs
"""
def ig_stories_url(access_token, ig_user_id),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{ig_user_id}/stories")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token
})
)
|> to_string()
def search_ig_user_url(access_token, ig_user_id, ig_username),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{ig_user_id}")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
fields:
"business_discovery.username(#{ig_username}){biography,public,ig_id,followers_count,follows_count,media_count,name,profile_picture_url,username,website}}"
})
)
|> to_string()
def feed_url(%{access_token: access_token, instagram_page_id: instagram_page_id} = params),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{instagram_page_id}/media")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
fields:
"is_comment_enabled,ig_id,permalink,shortcode,timestamp,thumbnail_url,username,caption,like_count",
after: Map.get(params, :after),
before: Map.get(params, :before)
})
)
|> to_string()
def media_object_url(access_token, instagram_media_id),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{instagram_media_id}")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
fields:
"caption,comments_count,is_comment_enabled,like_count,media_url,media_product_type,media_type,thumbnail_url,timestamp,username"
})
)
|> to_string()
def media_object_comments_url(access_token, instagram_media_id),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{instagram_media_id}/comments")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token
})
)
|> to_string()
def media_object_insights_url(
access_token,
instagram_media_id,
insight_merics \\ "ig_reels_avg_watch_time,ig_reels_video_view_total_time,likes,reach,saved,shares,total_interactions"
),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{instagram_media_id}/insights")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
metric: insight_merics
})
)
|> to_string()
@doc """
Maximum of 30 unique calls within 7 days
"""
def hashtag_search_url(access_token, hashtag, ig_user_id),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/ig_hashtag_search")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
q: hashtag,
user_id: ig_user_id
})
)
|> to_string()
def hashtag_recent_media_object_url(access_token, hashtag_id, ig_user_id),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{hashtag_id}/recent_media")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
fields:
"caption,comments_count,id,like_count,media_type,media_url,permalink,timestamp,children",
user_id: ig_user_id
})
)
|> to_string()
@doc """
30 Maximum unique hashtags within a 7 day period.
Does not return the username of the publisher
"""
def hashtag_top_media_object_url(access_token, hashtag_id, ig_user_id),
do:
access_token_endpoint()
|> URI.merge("/#{api_version()}/#{hashtag_id}/top_media")
|> Map.put(
:query,
URI.encode_query(%{
access_token: access_token,
fields:
"caption,comments_count,id,like_count,media_type,media_url,permalink,timestamp,children",
user_id: ig_user_id
})
)
|> to_string()
def user_info(access_token, ig_user_id) do
with {:ok, %Req.Response{body: response}} <-
Req.get(user_info_url(access_token, ig_user_id)) do
{:ok, response}
else
error ->
{:error, error}
end
end
def user_insights(access_token, ig_user_id) do
with {:ok, %Req.Response{body: body}} <-
Req.get(user_insights_url(access_token, ig_user_id)),
%{
"data" => [
%{
"name" => "reach",
"title" => "Reach",
"values" => reach_values
} = _reach_details,
%{
"name" => "impressions",
"title" => "Impressions",
"values" => impression_values
} = _impressions_details
]
} = _ <- body do
[impression_value | _] = impression_values
[reach_value | _] = reach_values
{:ok,
%{
"impressions" => Map.get(impression_value, "value"),
"reach" => Map.get(reach_value, "value")
}}
else
error ->
{:error, error}
end
end
def feed(%{access_token: access_token, instagram_page_id: instagram_page_id} = params) do
url =
feed_url(%{
access_token: access_token,
instagram_page_id: instagram_page_id,
after: Map.get(params, :after),
before: Map.get(params, :before)
})
with {:ok, %Req.Response{body: body}} <-
Req.get(url),
{:ok, response} <- Jason.decode(body) do
{:ok, cursor_based_media_pagination(response, params)}
else
error ->
{:error, error}
{:ok, []}
end
end
def cursor_based_media_pagination(
%{
"data" => []
},
_
),
do: []
def cursor_based_media_pagination(
%{
"data" => data,
"paging" => %{"cursors" => %{"after" => next, "before" => _}}
},
params
) do
case feed(Map.merge(params, %{after: next})) do
{:ok, second_call} ->
Enum.concat(data, second_call)
|> Enum.reduce_while([], fn current_item, acc ->
cond do
is_map(current_item) ->
{:cont, [current_item] ++ acc}
is_binary(current_item) ->
{:cont, [current_item] ++ acc}
true ->
{:cont, acc}
end
end)
_ ->
Enum.concat(data, [])
|> Enum.reduce_while([], fn current_item, acc ->
cond do
is_map(current_item) ->
{:cont, [current_item] ++ acc}
is_binary(current_item) ->
{:cont, [current_item] ++ acc}
true ->
{:cont, acc}
end
end)
end
end
def cursor_based_media_pagination(
_,
_
),
do: []
end