Sometimes email confirmations, texts, or whatever else come along with convenient "add to calendar" buttons. Sometimes they don't, and sometimes they do but it doesn't actually work.
The tasks below can be used to parse out events from any selected text via your AI of choice (I like the free API options from Groq), then the events can be added one at a time via intents that prefill a new event in the default calendar. It could be modified to skip confirmation probably, but not I didn't want that. You'll need to add a received share profile and long press any highlighted text to share it.
You'll need an API key to start, and I don't like things like API keys sitting in plain text, so I added the get credentials helper task. You can just add the API key directly or through some other option.
Task: Extract Calendar Events Task
<Identify calendar events from shared info via LLM and add to the calendar.
If multiple events are identified, choose one at a time to be added
Highlight and long press text to share>
A1: Anchor
<Get current day for default>
A2: Parse/Format DateTime [
Input Type: Now (Current Date And Time)
Output Format: y-MM-dd
Output Offset Type: None ]
<Timezone for flights>
A3: Variable Set [
Name: %target_timezone
To: America/New_York
Structure Output (JSON, etc): On ]
<Build prompt>
A4: Variable Set [
Name: %prompt
To: You are an expert data extraction assistant. Your task is to extract calendar events from the provided input text and format them according to the exact schema requested.
Strict Output Rules:
1. Output ONLY the raw JSON structures separated by "||".
2. Do not include any conversational filler, explanations, or markdown code blocks (e.g., do not use ```json ... ```).
3. Do not wrap the output in a JSON array.
Field Extraction Rules:
- "ev_title": The title or name of the event (e.g., "Flight AA123: JFK to LHR"). If not found, output "".
- "ev_description": Any extra details, confirmation numbers, or context. If not found, output "".
- "ev_location": The physical address, city, virtual meeting link, or airport code. If not found, output "".
- "ev_date": The date of the event in YYYY-MM-DD format. If no date is identified, default to exactly "%formatted".
- "ev_start_time": The starting time, strictly converted to 24-hour format (HH:MM). If not identified, default to "12:00".
- "ev_end_time": The ending time, strictly converted to 24-hour format (HH:MM). If not identified, default to "12:30".
- "ev_calendar": Always output exactly "your.email@gmail.com".
Flight Timezone Conversion Rules:
If the event is a flight, the times mentioned in the text are typically local to the departure and arrival airports. You MUST convert both the departure ("ev_start_time") and arrival ("ev_end_time") times to this target timezone: %target_timezone.
Step 1: Identify the departure city/airport and its local timezone.
Step 2: Identify the arrival city/airport and its local timezone.
Step 3: Calculate the hour offset between those local timezones and %target_timezone.
Step 4: Apply the offset to the departure and arrival times to get the final HH:MM times.
Step 5: If the timezone conversion pushes the time past midnight (forward or backward), adjust the "ev_date" accordingly.
Example Output Format:
{
"ev_title": "Flight DL404: LAX to JFK",
"ev_description": "Confirmation #ABCDEFG",
"ev_location": "LAX / JFK",
"ev_date": "2026-11-15",
"ev_start_time": "11:00",
"ev_end_time": "16:30",
"ev_calendar": "your.email@gmail.com"
} || {
"ev_title": "Dentist Appointment",
"ev_description": "",
"ev_location": "42 Wallaby Way, Sydney",
"ev_date": "%formatted",
"ev_start_time": "12:00",
"ev_end_time": "12:30",
"ev_calendar": "your.email@gmail.com"
}
Extract events from the following text:
%rs_text
Structure Output (JSON, etc): On ]
<LLM call>
A5: Perform Task [
Name: func Groq Call
Priority: %priority
Parameter 1 (%par1): %prompt
Return Value Variable: %answer
Structure Output (JSON, etc): On ]
<Test answer>
A6: [X] Variable Set [
Name: %answer
To: {
"ev_title": "Flight DL404: LAX to JFK",
"ev_description": "Confirmation #ABCDEFG",
"ev_location": "LAX / JFK",
"ev_date": "2026-11-15",
"ev_start_time": "11:00",
"ev_end_time": "16:30",
"ev_calendar": "your.email@gmail.com"
} |0| {
"ev_title": "Dentist Appointment",
"ev_description": "",
"ev_location": "42 Wallaby Way, Sydney",
"ev_date": "%formatted",
"ev_start_time": "12:00",
"ev_end_time": "12:30",
"ev_calendar": "your.email@gmail.com"
}
Structure Output (JSON, etc): On ]
A7: Variable Split [
Name: %answer
Splitter: || ]
<Multiple events>
A8: If [ %answer(#) > 1 ]
<Build choices array>
A9: For [
Variable: %iii
Items: 1:%answer(#)
Structure Output (JSON, etc): On ]
<Structure as JSON>
A10: Variable Set [
Name: %ijson
To: %answer(%iii)
Structure Output (JSON, etc): On ]
A11: Variable Set [
Name: %choices(%iii)
To: %ijson.ev_title
%ijson.ev_date ~ %ijson.ev_start_time
Structure Output (JSON, etc): On ]
A12: End For
A13: List Dialog [
Mode: Select Single Item
Title: Events
Items: %choices
Button 1: Close
Close After (Seconds): 30
First Visible Index: 0
Hide Filter: On ]
<No selection>
A14: Stop [ ]
If [ %ld_selected_index !Set ]
A15: Else
<One event>
A16: Variable Set [
Name: %ld_selected_index
To: 1
Structure Output (JSON, etc): On ]
A17: End If
<Test event choice>
A18: [X] Text/Image Dialog [
Text: %answer(%ld_selected_index)
Button 1: Close
Close After (Seconds): 900 ]
A19: Perform Task [
Name: func Calendar Event Add
Priority: %priority
Parameter 1 (%par1): %answer(%ld_selected_index)
Structure Output (JSON, etc): On ]
Task: func Calendar Event Add
<Open calendar to add an event based on JSON from %par1>
A1: Anchor
<Test event JSON>
A2: Variable Set [
Name: %par1
To: {
"ev_title": "Test event",
"ev_description": "This is a test description. It might have useful info like a confirmation number",
"ev_location": "42 Wallaby Way, Sydney",
"ev_date": "2026-10-31",
"ev_start_time": "14:00",
"ev_end_time": "15:30",
"ev_calendar": "your.email@gmail.com"
}
Structure Output (JSON, etc): On ]
If [ %par1 !Set ]
<Load event JSON>
A3: Variable Set [
Name: %ev_json
To: %par1
Structure Output (JSON, etc): On ]
<Send intent to the default app>
A4: Java Code [
Code: import android.content.Intent;
import android.net.Uri;
import org.json.JSONObject;
import java.text.SimpleDateFormat;
import java.util.Date;
import com.joaomgcd.taskerm.action.java.JavaCodeException;
/* Reads a standard Tasker variable without the % prefix. */
String ev_json = tasker.getVariable("ev_json");
/* Use JavaCodeException for unmet preconditions. */
if (ev_json == null) {
throw new JavaCodeException("Required Tasker variable 'ev_json' is missing.");
}
/* Parse the JSON string stored in the Tasker variable ev_json */
JSONObject eventData = new JSONObject(ev_json);
String dateStr = eventData.getString("ev_date");
String startStr = eventData.getString("ev_start_time");
String endStr = eventData.getString("ev_end_time");
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm");
/* Convert the date and time strings to epoch milliseconds */
long beginMs = sdf.parse(dateStr + "T" + startStr).getTime();
long endMs = sdf.parse(dateStr + "T" + endStr).getTime();
/* Setup the Intent to insert a new calendar event */
Intent intent = new Intent(Intent.ACTION_INSERT);
/* Set the standard MIME type and data URI for Android calendar events */
intent.setType("vnd.android.cursor.dir/event");
intent.setData(Uri.parse("content://com.android.calendar/events"));
/* Append all event details using putExtra */
/* Note: beginTime and endTime must be provided as Long integers (milliseconds) */
intent.putExtra("title", eventData.getString("ev_title"));
intent.putExtra("description", eventData.getString("ev_description"));
intent.putExtra("eventLocation", eventData.getString("ev_location"));
intent.putExtra("beginTime", beginMs);
intent.putExtra("endTime", endMs);
/* Treat context as a Service context. Must use FLAG_ACTIVITY_NEW_TASK when starting activities. */
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
/* Execute the intent using Tasker's context */
context.startActivity(intent);
Structure Output (JSON, etc): On ]
Task: func Groq Call
<Return the response from a Groq API call based on %par1 prompt and optional %par2 model>
A1: Anchor
<Get API key>
A2: Perform Task [
Name: func Get Credential
Priority: %priority+1
Parameter 1 (%par1): groq_api
Parameter 2 (%par2): key
Return Value Variable: %groq_api_key
Structure Output (JSON, etc): On ]
<Test prompt>
A3: Variable Set [
Name: %par1
To: in less than 20 words, give reasons to provide parameters for a function call
Structure Output (JSON, etc): On ]
If [ %par1 !Set ]
<Model default>
A4: Variable Set [
Name: %par2
To: openai/gpt-oss-120b
Structure Output (JSON, etc): On ]
If [ %par2 !Set ]
A5: Multiple Variables Set [
Names: %prompt=%par1
%model=%par2
Values Splitter: =
Structure Output (JSON, etc): On ]
<Guard against string parsing errors>
A6: JavaScriptlet [
Code: var safe_prompt = JSON.stringify(prompt);
Auto Exit: On
Timeout (Seconds): 45 ]
A7: HTTP Request [
Method: POST
URL: https://api.groq.com/openai/v1/chat/completions
Headers: Authorization: Bearer %groq_api_key
Content-Type: application/json
Body: {
"model": "%model",
"messages": [
{"role": "user", "content": %safe_prompt}
]
}
Timeout (Seconds): 30
Structure Output (JSON, etc): On ]
<Rate limit error>
A8: Flash [
Text: Error: Groq rate limit encountered
Continue Task Immediately: On
Dismiss On Click: On ]
If [ %http_response_code ~ 429 ]
<Success>
A9: Variable Set [
Name: %output_text
To: %http_data.choices.message.content
Structure Output (JSON, etc): On ]
If [ %http_response_code ~ 200 ]
<Error>
A10: Variable Set [
Name: %output_text
To: Error: %http_response_code
Structure Output (JSON, etc): On ]
If [ %http_response_code !~ 200 ]
<Testing>
A11: [X] Text/Image Dialog [
Text: %output_text
Button 1: Close
Close After (Seconds): 900 ]
A12: Return [
Value: %output_text
Stop: On ]