Insights Api
The insights API shares most of the fields between a thread and a user as a whole, so the way our types are modeled, you should be able to pull data without major issues sharing the same content.
#r "nuget: Threads.Lib"
open System
open Threads.Lib
open Threads.Lib.Insights
let client =
Environment.GetEnvironmentVariable("THREADS_ACCESS_TOKEN") |> Threads.Create
type DataRange =
| Week
| Month
| Year
let prepareInsightsParams range = [
let minDate =
// The Threads Insights API only supports data from after June 2, 2024
DateTimeOffset(DateOnly(2024, 6, 2), TimeOnly(0, 0), TimeSpan.Zero)
match range with
| Week -> Since(DateTimeOffset.Now.AddDays(-7.))
| Month -> Since(DateTimeOffset.Now.AddDays(-30.))
| Year ->
let targetDate = DateTimeOffset.Now.AddDays(-365.)
let targetDate = if targetDate < minDate then minDate else targetDate
Since(targetDate)
Until(DateTimeOffset.Now)
]
task {
let insightParams = prepareInsightsParams Year
let! response =
client.Insights.FetchUserInsights(
"me",
[ Views; Likes; Replies; Reposts; Quotes; FollowerCount ],
insightParams
)
printfn "%A" response
}
|> Async.AwaitTask
|> Async.RunSynchronously
Running the code above will give you an output similar to this:
{ data =[
[Name Views; Period Day; Title "Views";
Description "Number of views of your profile.";
Id "0123456789/insights/views/day";
Values [{ value = 3u; endTime = ValueSome 6/1/2024 7:00:00
[Name Likes; Period Day; Title "Likes";
Description "Numberof Likes in your posts";
Id "0123456789/insights/likes/day"; TotalValue 292u];
[Name Replies; Period Day; Title "Replies";
Description "Number of replies in your posts";
Id "0123456789/insights/replies/day"; TotalValue 148u];
[Name Reposts; Period Day; Title "reposts";
Description "Number of reposts in your posts.";
Id "0123456789/insights/reposts/day"; TotalValue 40u];
[Name Quotes; Period Day; Title "citas";
Description "Number of quotes of your posts.";
Id "0123456789/insights/quotes/day"; TotalValue 50u];
[Name FollowerCount; Period Day; Title "followers_count";
Description "Number of your followers on threads.";
Id "0123456789/insights/followers_count/day"; TotalValue 301u]
]
}
The only "row" that distinguishes itself from the others is the "Views" one where rather than delivering a "TotalValue" it brings a Values list, this can be plotted to have a nice view of how much views you were getting between periods of time
If you add Plotly.NET
you can easily generate an HTML embedable chart
#r "nuget: Threads.Lib, 1.0.0-beta-002"
#r "nuget: Plotly.NET, 5.0.0"
open System
// Added!
open Plotly.NET
open Threads.Lib
open Threads.Lib.Insights
let client =
Environment.GetEnvironmentVariable("THREADS_ACCESS_TOKEN") |> Threads.Create
type DataRange =
| Week
| Month
| Year
let prepareInsightsParams range = [
let minDate =
// The Threads Insights API only supports data from after June 2, 2024
DateTimeOffset(DateOnly(2024, 6, 2), TimeOnly(0, 0), TimeSpan.Zero)
match range with
| Week -> Since(DateTimeOffset.Now.AddDays(-7.))
| Month -> Since(DateTimeOffset.Now.AddDays(-30.))
| Year ->
let targetDate = DateTimeOffset.Now.AddDays(-365.)
let targetDate = if targetDate < minDate then minDate else targetDate
Since(targetDate)
Until(DateTimeOffset.Now)
]
// Added!
let plotViews(views: MetricValue list) =
let plotPoints =
views
|> List.map(fun v ->
v.endTime.Value.DateTime.ToShortDateString(), int v.value)
Chart.Line(plotPoints, Name = "Views")
|> Chart.withTitle("Views over time")
|> Chart.withSize(800., 600.)
|> Chart.show
task {
let insightParams = prepareInsightsParams Year
let! response =
client.Insights.FetchUserInsights(
"me",
[ Views; Likes; Replies; Reposts; Quotes; FollowerCount ],
insightParams
)
let viewsOnly =
let pickViews =
List.tryPick(fun m ->
match m with
| Values v -> Some v
| _ -> None)
// Pick the first MetricValue list (which is usually the views one)
// you can update the match expression above to be more rigorous about it
List.tryPick (pickViews) response.data |> Option.defaultValue []
plotViews viewsOnly
}
|> Async.AwaitTask
|> Async.RunSynchronously
If all goes well a new browser tab will be open with your interactive chart ready to go, in this case I just exported the image for you to see.
namespace System
val client: obj
type Environment =
static member Exit: exitCode: int -> unit
static member ExpandEnvironmentVariables: name: string -> string
static member FailFast: message: string -> unit + 1 overload
static member GetCommandLineArgs: unit -> string array
static member GetEnvironmentVariable: variable: string -> string + 1 overload
static member GetEnvironmentVariables: unit -> IDictionary + 1 overload
static member GetFolderPath: folder: SpecialFolder -> string + 1 overload
static member GetLogicalDrives: unit -> string array
static member SetEnvironmentVariable: variable: string * value: string -> unit + 1 overload
static member CommandLine: string
...
<summary>Provides information about, and means to manipulate, the current environment and platform. This class cannot be inherited.</summary>
<summary>Provides information about, and means to manipulate, the current environment and platform. This class cannot be inherited.</summary>
Environment.GetEnvironmentVariable(variable: string) : string
Environment.GetEnvironmentVariable(variable: string, target: EnvironmentVariableTarget) : string
Environment.GetEnvironmentVariable(variable: string, target: EnvironmentVariableTarget) : string
type DataRange =
| Week
| Month
| Year
val prepareInsightsParams: range: DataRange -> 'a list
val range: DataRange
val minDate: DateTimeOffset
Multiple items
[<Struct>] type DateTimeOffset = new: dateTime: DateTime -> unit + 8 overloads member Add: timeSpan: TimeSpan -> DateTimeOffset member AddDays: days: float -> DateTimeOffset member AddHours: hours: float -> DateTimeOffset member AddMicroseconds: microseconds: float -> DateTimeOffset member AddMilliseconds: milliseconds: float -> DateTimeOffset member AddMinutes: minutes: float -> DateTimeOffset member AddMonths: months: int -> DateTimeOffset member AddSeconds: seconds: float -> DateTimeOffset member AddTicks: ticks: int64 -> DateTimeOffset ...
<summary>Represents a point in time, typically expressed as a date and time of day, relative to Coordinated Universal Time (UTC).</summary>
--------------------
DateTimeOffset ()
DateTimeOffset(dateTime: DateTime) : DateTimeOffset
DateTimeOffset(dateTime: DateTime, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(ticks: int64, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(date: DateOnly, time: TimeOnly, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, microsecond: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, microsecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : DateTimeOffset
[<Struct>] type DateTimeOffset = new: dateTime: DateTime -> unit + 8 overloads member Add: timeSpan: TimeSpan -> DateTimeOffset member AddDays: days: float -> DateTimeOffset member AddHours: hours: float -> DateTimeOffset member AddMicroseconds: microseconds: float -> DateTimeOffset member AddMilliseconds: milliseconds: float -> DateTimeOffset member AddMinutes: minutes: float -> DateTimeOffset member AddMonths: months: int -> DateTimeOffset member AddSeconds: seconds: float -> DateTimeOffset member AddTicks: ticks: int64 -> DateTimeOffset ...
<summary>Represents a point in time, typically expressed as a date and time of day, relative to Coordinated Universal Time (UTC).</summary>
--------------------
DateTimeOffset ()
DateTimeOffset(dateTime: DateTime) : DateTimeOffset
DateTimeOffset(dateTime: DateTime, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(ticks: int64, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(date: DateOnly, time: TimeOnly, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, microsecond: int, offset: TimeSpan) : DateTimeOffset
DateTimeOffset(year: int, month: int, day: int, hour: int, minute: int, second: int, millisecond: int, microsecond: int, calendar: Globalization.Calendar, offset: TimeSpan) : DateTimeOffset
Multiple items
[<Struct>] type DateOnly = new: year: int * month: int * day: int -> unit + 1 overload member AddDays: value: int -> DateOnly member AddMonths: value: int -> DateOnly member AddYears: value: int -> DateOnly member CompareTo: value: DateOnly -> int + 1 overload member Deconstruct: year: byref<int> * month: byref<int> * day: byref<int> -> unit member Equals: value: DateOnly -> bool + 1 overload member GetHashCode: unit -> int member ToDateTime: time: TimeOnly -> DateTime + 1 overload member ToLongDateString: unit -> string ...
<summary>Represents dates with values ranging from January 1, 0001 Anno Domini (Common Era) through December 31, 9999 A.D. (C.E.) in the Gregorian calendar.</summary>
--------------------
DateOnly ()
DateOnly(year: int, month: int, day: int) : DateOnly
DateOnly(year: int, month: int, day: int, calendar: Globalization.Calendar) : DateOnly
[<Struct>] type DateOnly = new: year: int * month: int * day: int -> unit + 1 overload member AddDays: value: int -> DateOnly member AddMonths: value: int -> DateOnly member AddYears: value: int -> DateOnly member CompareTo: value: DateOnly -> int + 1 overload member Deconstruct: year: byref<int> * month: byref<int> * day: byref<int> -> unit member Equals: value: DateOnly -> bool + 1 overload member GetHashCode: unit -> int member ToDateTime: time: TimeOnly -> DateTime + 1 overload member ToLongDateString: unit -> string ...
<summary>Represents dates with values ranging from January 1, 0001 Anno Domini (Common Era) through December 31, 9999 A.D. (C.E.) in the Gregorian calendar.</summary>
--------------------
DateOnly ()
DateOnly(year: int, month: int, day: int) : DateOnly
DateOnly(year: int, month: int, day: int, calendar: Globalization.Calendar) : DateOnly
Multiple items
[<Struct>] type TimeOnly = new: hour: int * minute: int -> unit + 4 overloads member Add: value: TimeSpan -> TimeOnly + 1 overload member AddHours: value: float -> TimeOnly + 1 overload member AddMinutes: value: float -> TimeOnly + 1 overload member CompareTo: value: obj -> int + 1 overload member Deconstruct: hour: byref<int> * minute: byref<int> -> unit + 3 overloads member Equals: value: obj -> bool + 1 overload member GetHashCode: unit -> int member IsBetween: start: TimeOnly * ``end`` : TimeOnly -> bool member ToLongTimeString: unit -> string ...
<summary>Represents a time of day, as would be read from a clock, within the range 00:00:00 to 23:59:59.9999999.</summary>
--------------------
TimeOnly ()
TimeOnly(ticks: int64) : TimeOnly
TimeOnly(hour: int, minute: int) : TimeOnly
TimeOnly(hour: int, minute: int, second: int) : TimeOnly
TimeOnly(hour: int, minute: int, second: int, millisecond: int) : TimeOnly
TimeOnly(hour: int, minute: int, second: int, millisecond: int, microsecond: int) : TimeOnly
[<Struct>] type TimeOnly = new: hour: int * minute: int -> unit + 4 overloads member Add: value: TimeSpan -> TimeOnly + 1 overload member AddHours: value: float -> TimeOnly + 1 overload member AddMinutes: value: float -> TimeOnly + 1 overload member CompareTo: value: obj -> int + 1 overload member Deconstruct: hour: byref<int> * minute: byref<int> -> unit + 3 overloads member Equals: value: obj -> bool + 1 overload member GetHashCode: unit -> int member IsBetween: start: TimeOnly * ``end`` : TimeOnly -> bool member ToLongTimeString: unit -> string ...
<summary>Represents a time of day, as would be read from a clock, within the range 00:00:00 to 23:59:59.9999999.</summary>
--------------------
TimeOnly ()
TimeOnly(ticks: int64) : TimeOnly
TimeOnly(hour: int, minute: int) : TimeOnly
TimeOnly(hour: int, minute: int, second: int) : TimeOnly
TimeOnly(hour: int, minute: int, second: int, millisecond: int) : TimeOnly
TimeOnly(hour: int, minute: int, second: int, millisecond: int, microsecond: int) : TimeOnly
Multiple items
[<Struct>] type TimeSpan = new: hours: int * minutes: int * seconds: int -> unit + 4 overloads member Add: ts: TimeSpan -> TimeSpan member CompareTo: value: obj -> int + 1 overload member Divide: divisor: float -> TimeSpan + 1 overload member Duration: unit -> TimeSpan member Equals: value: obj -> bool + 2 overloads member GetHashCode: unit -> int member Multiply: factor: float -> TimeSpan member Negate: unit -> TimeSpan member Subtract: ts: TimeSpan -> TimeSpan ...
<summary>Represents a time interval.</summary>
--------------------
TimeSpan ()
TimeSpan(ticks: int64) : TimeSpan
TimeSpan(hours: int, minutes: int, seconds: int) : TimeSpan
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : TimeSpan
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : TimeSpan
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int, microseconds: int) : TimeSpan
[<Struct>] type TimeSpan = new: hours: int * minutes: int * seconds: int -> unit + 4 overloads member Add: ts: TimeSpan -> TimeSpan member CompareTo: value: obj -> int + 1 overload member Divide: divisor: float -> TimeSpan + 1 overload member Duration: unit -> TimeSpan member Equals: value: obj -> bool + 2 overloads member GetHashCode: unit -> int member Multiply: factor: float -> TimeSpan member Negate: unit -> TimeSpan member Subtract: ts: TimeSpan -> TimeSpan ...
<summary>Represents a time interval.</summary>
--------------------
TimeSpan ()
TimeSpan(ticks: int64) : TimeSpan
TimeSpan(hours: int, minutes: int, seconds: int) : TimeSpan
TimeSpan(days: int, hours: int, minutes: int, seconds: int) : TimeSpan
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int) : TimeSpan
TimeSpan(days: int, hours: int, minutes: int, seconds: int, milliseconds: int, microseconds: int) : TimeSpan
field TimeSpan.Zero: TimeSpan
union case DataRange.Week: DataRange
property DateTimeOffset.Now: DateTimeOffset with get
<summary>Gets a <see cref="T:System.DateTimeOffset" /> object that is set to the current date and time on the current computer, with the offset set to the local time's offset from Coordinated Universal Time (UTC).</summary>
<returns>A <see cref="T:System.DateTimeOffset" /> object whose date and time is the current local time and whose offset is the local time zone's offset from Coordinated Universal Time (UTC).</returns>
<summary>Gets a <see cref="T:System.DateTimeOffset" /> object that is set to the current date and time on the current computer, with the offset set to the local time's offset from Coordinated Universal Time (UTC).</summary>
<returns>A <see cref="T:System.DateTimeOffset" /> object whose date and time is the current local time and whose offset is the local time zone's offset from Coordinated Universal Time (UTC).</returns>
DateTimeOffset.AddDays(days: float) : DateTimeOffset
union case DataRange.Month: DataRange
union case DataRange.Year: DataRange
val targetDate: DateTimeOffset
val task: TaskBuilder
val insightParams: obj list
val response: obj
val printfn: format: Printf.TextWriterFormat<'T> -> 'T
Multiple items
type Async = static member AsBeginEnd: computation: ('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit) static member AwaitEvent: event: IEvent<'Del,'T> * ?cancelAction: (unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate) static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int -> Async<bool> static member AwaitTask: task: Task<'T> -> Async<'T> + 1 overload static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int -> Async<bool> static member CancelDefaultToken: unit -> unit static member Catch: computation: Async<'T> -> Async<Choice<'T,exn>> static member Choice: computations: Async<'T option> seq -> Async<'T option> static member FromBeginEnd: beginAction: (AsyncCallback * obj -> IAsyncResult) * endAction: (IAsyncResult -> 'T) * ?cancelAction: (unit -> unit) -> Async<'T> + 3 overloads static member FromContinuations: callback: (('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T> ...
--------------------
type Async<'T>
type Async = static member AsBeginEnd: computation: ('Arg -> Async<'T>) -> ('Arg * AsyncCallback * obj -> IAsyncResult) * (IAsyncResult -> 'T) * (IAsyncResult -> unit) static member AwaitEvent: event: IEvent<'Del,'T> * ?cancelAction: (unit -> unit) -> Async<'T> (requires delegate and 'Del :> Delegate) static member AwaitIAsyncResult: iar: IAsyncResult * ?millisecondsTimeout: int -> Async<bool> static member AwaitTask: task: Task<'T> -> Async<'T> + 1 overload static member AwaitWaitHandle: waitHandle: WaitHandle * ?millisecondsTimeout: int -> Async<bool> static member CancelDefaultToken: unit -> unit static member Catch: computation: Async<'T> -> Async<Choice<'T,exn>> static member Choice: computations: Async<'T option> seq -> Async<'T option> static member FromBeginEnd: beginAction: (AsyncCallback * obj -> IAsyncResult) * endAction: (IAsyncResult -> 'T) * ?cancelAction: (unit -> unit) -> Async<'T> + 3 overloads static member FromContinuations: callback: (('T -> unit) * (exn -> unit) * (OperationCanceledException -> unit) -> unit) -> Async<'T> ...
--------------------
type Async<'T>
static member Async.AwaitTask: task: Threading.Tasks.Task -> Async<unit>
static member Async.AwaitTask: task: Threading.Tasks.Task<'T> -> Async<'T>
static member Async.AwaitTask: task: Threading.Tasks.Task<'T> -> Async<'T>
static member Async.RunSynchronously: computation: Async<'T> * ?timeout: int * ?cancellationToken: Threading.CancellationToken -> 'T
union case ValueOption.ValueSome: 'T -> ValueOption<'T>
val plotViews: views: 'a list -> 'b
val views: 'a list
type 'T list = List<'T>
val plotPoints: (obj * int) list
Multiple items
module List from Microsoft.FSharp.Collections
--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T member IsEmpty: bool member Item: index: int -> 'T with get ...
module List from Microsoft.FSharp.Collections
--------------------
type List<'T> = | op_Nil | op_ColonColon of Head: 'T * Tail: 'T list interface IReadOnlyList<'T> interface IReadOnlyCollection<'T> interface IEnumerable interface IEnumerable<'T> member GetReverseIndex: rank: int * offset: int -> int member GetSlice: startIndex: int option * endIndex: int option -> 'T list static member Cons: head: 'T * tail: 'T list -> 'T list member Head: 'T member IsEmpty: bool member Item: index: int -> 'T with get ...
val map: mapping: ('T -> 'U) -> list: 'T list -> 'U list
val v: 'a
Multiple items
val int: value: 'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> = int
val int: value: 'T -> int (requires member op_Explicit)
--------------------
type int = int32
--------------------
type int<'Measure> = int
val viewsOnly: obj list
val pickViews: (obj list -> obj list option)
val tryPick: chooser: ('T -> 'U option) -> list: 'T list -> 'U option
val m: obj
val v: obj list
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
module Option
from Microsoft.FSharp.Core
val defaultValue: value: 'T -> option: 'T option -> 'T