{"id":15318427,"url":"https://github.com/appleboy/go-fcm","last_synced_at":"2025-12-24T13:45:59.782Z","repository":{"id":43288354,"uuid":"93027591","full_name":"appleboy/go-fcm","owner":"appleboy","description":"Firebase Cloud Messaging Library for Golang","archived":false,"fork":false,"pushed_at":"2025-05-05T21:08:47.000Z","size":277,"stargazers_count":293,"open_issues_count":3,"forks_count":74,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-05-06T18:29:10.169Z","etag":null,"topics":["android","firebase","notification"],"latest_commit_sha":null,"homepage":null,"language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/appleboy.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":null,"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":["https://www.paypal.me/appleboy46"]}},"created_at":"2017-06-01T07:11:13.000Z","updated_at":"2025-05-05T11:20:43.000Z","dependencies_parsed_at":"2024-11-06T16:36:29.947Z","dependency_job_id":"fdad8ced-b3e2-4c48-8372-06f29f4f973e","html_url":"https://github.com/appleboy/go-fcm","commit_stats":{"total_commits":149,"total_committers":16,"mean_commits":9.3125,"dds":0.3489932885906041,"last_synced_commit":"79ad4390fbccdf6b2ac7be0da7ca5d08a6c3d386"},"previous_names":[],"tags_count":15,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appleboy%2Fgo-fcm","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appleboy%2Fgo-fcm/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appleboy%2Fgo-fcm/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/appleboy%2Fgo-fcm/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/appleboy","download_url":"https://codeload.github.com/appleboy/go-fcm/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253516669,"owners_count":21920715,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["android","firebase","notification"],"created_at":"2024-10-01T09:00:02.716Z","updated_at":"2025-12-24T13:45:59.768Z","avatar_url":"https://github.com/appleboy.png","language":"Go","funding_links":["https://www.paypal.me/appleboy46"],"categories":[],"sub_categories":[],"readme":"# go-fcm\n\n[English](README.md) | [繁體中文](README.zh-tw.md) | [简体中文](README.zh-cn.md)\n\n[![GoDoc](https://pkg.go.dev/badge/github.com/appleboy/go-fcm)](https://pkg.go.dev/github.com/appleboy/go-fcm)\n[![Lint and Testing](https://github.com/appleboy/go-fcm/actions/workflows/testing.yml/badge.svg?branch=master)](https://github.com/appleboy/go-fcm/actions/workflows/testing.yml)\n[![Trivy Security Scan](https://github.com/appleboy/go-fcm/actions/workflows/trivy.yml/badge.svg?branch=master)](https://github.com/appleboy/go-fcm/actions/workflows/trivy.yml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/appleboy/go-fcm)](https://goreportcard.com/report/github.com/appleboy/go-fcm)\n\n\u003e Forked from [github.com/edganiukov/fcm](https://github.com/edganiukov/fcm)  \n\u003e [Firebase Cloud Messaging Official Documentation](https://firebase.google.com/docs/cloud-messaging/)\n\n---\n\n## Table of Contents\n\n- [go-fcm](#go-fcm)\n  - [Table of Contents](#table-of-contents)\n  - [Features](#features)\n  - [Supported Message Types](#supported-message-types)\n  - [Quick Start](#quick-start)\n  - [Authentication and Credentials](#authentication-and-credentials)\n  - [Usage Example](#usage-example)\n  - [Advanced Configuration](#advanced-configuration)\n    - [Custom HTTP Client](#custom-http-client)\n    - [Proxy Support](#proxy-support)\n    - [Unit Testing and Mock](#unit-testing-and-mock)\n  - [Best Practices](#best-practices)\n  - [Troubleshooting](#troubleshooting)\n  - [Architecture Diagram](#architecture-diagram)\n  - [FAQ](#faq)\n  - [License](#license)\n\n---\n\n## Features\n\n| Feature                   | Supported | Description                                 |\n| ------------------------- | :-------: | ------------------------------------------- |\n| Single Device Messaging   |    ✅     | Send messages to a single device            |\n| Multiple Device Messaging |    ✅     | Send messages to multiple devices           |\n| Topic Messaging           |    ✅     | Send messages to a specific topic           |\n| Condition Messaging       |    ✅     | Support for FCM condition syntax            |\n| Custom HTTP Client        |    ✅     | Custom timeout, proxy, and transport config |\n| Multiple Message Formats  |    ✅     | Data, Notification, Multicast               |\n| Unit Test \u0026 Mock Support  |    ✅     | Easy unit testing with mock client          |\n\n---\n\n## Supported Message Types\n\n| Type         | Description                                             |\n| ------------ | ------------------------------------------------------- |\n| Data         | Custom data messages, handled by the app                |\n| Notification | System notification messages, shown in notification bar |\n| Multicast    | Send to up to 500 device tokens at once                 |\n| Topic        | Send to all devices subscribed to a topic               |\n| Condition    | Send to devices matching a logical condition            |\n\n---\n\n## Quick Start\n\nInstall go-fcm:\n\n```bash\ngo get github.com/appleboy/go-fcm\n```\n\n---\n\n## Authentication and Credentials\n\nIt is recommended to use Google Application Default Credentials (ADC) for authentication.  \nDownload the JSON key from [Firebase Console \u003e Settings \u003e Service Accounts][11] and set the environment variable:\n\n```bash\nexport GOOGLE_APPLICATION_CREDENTIALS=\"/path/to/serviceAccountKey.json\"\n```\n\nAlternatively, specify the key path directly in your code.\n\n[11]: https://console.firebase.google.com/project/_/settings/serviceaccounts/adminsdk\n\n---\n\n## Usage Example\n\n```go\npackage main\n\nimport (\n  \"context\"\n  \"fmt\"\n  \"log\"\n\n  \"firebase.google.com/go/v4/messaging\"\n  fcm \"github.com/appleboy/go-fcm\"\n)\n\nfunc main() {\n  ctx := context.Background()\n  client, err := fcm.NewClient(\n    ctx,\n    fcm.WithCredentialsFile(\"path/to/serviceAccountKey.json\"),\n    // fcm.WithServiceAccount(\"my-client-id@my-project-id.iam.gserviceaccount.com\"),\n  )\n  if err != nil {\n    log.Fatal(err)\n  }\n\n  // Send to a single device\n  token := \"YOUR_DEVICE_TOKEN\"\n  resp, err := client.Send(\n    ctx,\n    \u0026messaging.Message{\n      Token: token,\n      Data: map[string]string{\n        \"foo\": \"bar\",\n      },\n    },\n  )\n  if err != nil {\n    log.Fatal(err)\n  }\n  fmt.Println(\"Success:\", resp.SuccessCount, \"Failure:\", resp.FailureCount)\n\n  // Send to a topic\n  resp, err = client.Send(\n    ctx,\n    \u0026messaging.Message{\n      Data: map[string]string{\n        \"foo\": \"bar\",\n      },\n      Topic: \"highScores\",\n    },\n  )\n  if err != nil {\n    log.Fatal(err)\n  }\n\n  // Send with condition\n  condition := \"'stock-GOOG' in topics || 'industry-tech' in topics\"\n  message := \u0026messaging.Message{\n    Data: map[string]string{\n      \"score\": \"850\",\n      \"time\":  \"2:45\",\n    },\n    Condition: condition,\n  }\n  resp, err = client.Send(ctx, message)\n  if err != nil {\n    log.Fatal(err)\n  }\n\n  // Send to multiple devices\n  registrationToken := \"YOUR_REGISTRATION_TOKEN\"\n  messages := []*messaging.Message{\n    {\n      Notification: \u0026messaging.Notification{\n        Title: \"Price drop\",\n        Body:  \"5% off all electronics\",\n      },\n      Token: registrationToken,\n    },\n    {\n      Notification: \u0026messaging.Notification{\n        Title: \"Price drop\",\n        Body:  \"2% off all books\",\n      },\n      Topic: \"readers-club\",\n    },\n  }\n  resp, err = client.Send(ctx, messages...)\n  if err != nil {\n    log.Fatal(err)\n  }\n\n  // Multicast messaging\n  registrationTokens := []string{\n    \"YOUR_REGISTRATION_TOKEN_1\",\n    \"YOUR_REGISTRATION_TOKEN_2\",\n    // ...\n  }\n  msg := \u0026messaging.MulticastMessage{\n    Data: map[string]string{\n      \"score\": \"850\",\n      \"time\":  \"2:45\",\n    },\n    Tokens: registrationTokens,\n  }\n  resp, err = client.SendMulticast(ctx, msg)\n  if err != nil {\n    log.Fatal(err)\n  }\n  fmt.Printf(\"%d messages were sent successfully\\n\", resp.SuccessCount)\n  if resp.FailureCount \u003e 0 {\n    var failedTokens []string\n    for idx, resp := range resp.Responses {\n      if !resp.Success {\n        failedTokens = append(failedTokens, registrationTokens[idx])\n      }\n    }\n    fmt.Printf(\"List of tokens that caused failures: %v\\n\", failedTokens)\n  }\n}\n```\n\n---\n\n## Advanced Configuration\n\n### Custom HTTP Client\n\n```go\nimport (\n  \"crypto/tls\"\n  \"net\"\n  \"net/http\"\n  \"time\"\n  \"golang.org/x/net/http2\"\n)\n\nfunc main() {\n  httpTimeout := 5 * time.Second\n  tlsTimeout := 5 * time.Second\n\n  transport := \u0026http2.Transport{\n    DialTLS: func(network, addr string, cfg *tls.Config) (net.Conn, error) {\n      return tls.DialWithDialer(\u0026net.Dialer{Timeout: tlsTimeout}, network, addr, cfg)\n    },\n  }\n\n  httpClient := \u0026http.Client{\n    Transport: transport,\n    Timeout:   httpTimeout,\n  }\n\n  ctx := context.Background()\n  client, err := fcm.NewClient(\n    ctx,\n    fcm.WithCredentialsFile(\"path/to/serviceAccountKey.json\"),\n    fcm.WithHTTPClient(httpClient),\n  )\n}\n```\n\n### Proxy Support\n\n```go\nfunc main() {\n  ctx := context.Background()\n  client, err := fcm.NewClient(\n    ctx,\n    fcm.WithCredentialsFile(\"path/to/serviceAccountKey.json\"),\n    fcm.WithHTTPProxy(\"http://localhost:8088\"),\n  )\n}\n```\n\n### Unit Testing and Mock\n\n```go\nimport (\n  \"context\"\n  \"net/http\"\n  \"net/http/httptest\"\n  \"testing\"\n\n  \"firebase.google.com/go/v4/messaging\"\n  fcm \"github.com/appleboy/go-fcm\"\n  \"google.golang.org/api/option\"\n)\n\nfunc TestMockClient(t *testing.T) {\n  server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n    w.WriteHeader(http.StatusOK)\n    w.Header().Set(\"Content-Type\", \"application/json\")\n    _, _ = w.Write([]byte(`{\"name\": \"q1w2e3r4\"}`))\n  }))\n  defer server.Close()\n\n  client, err := fcm.NewClient(\n    context.Background(),\n    fcm.WithEndpoint(server.URL),\n    fcm.WithProjectID(\"test\"),\n    fcm.WithCustomClientOption(option.WithoutAuthentication()),\n  )\n  if err != nil {\n    t.Fatalf(\"unexpected error: %v\", err)\n  }\n  resp, err := client.Send(\n    context.Background(),\n    \u0026messaging.Message{\n      Token: \"test\",\n      Data: map[string]string{\n        \"foo\": \"bar\",\n      },\n    })\n  if err != nil {\n    t.Fatalf(\"unexpected error: %v\", err)\n  }\n  // Check response\n  if resp.SuccessCount != 1 {\n    t.Fatalf(\"expected 1 successes, got: %d\", resp.SuccessCount)\n  }\n  if resp.FailureCount != 0 {\n    t.Fatalf(\"expected 0 failures, got: %d\", resp.FailureCount)\n  }\n}\n```\n\n---\n\n## Best Practices\n\n\u003e [!TIP]\n\u003e\n\u003e - For batch messaging, limit each batch to no more than 500 tokens.\n\u003e - Prefer using Topics to manage device groups instead of direct token management.\n\u003e - Set your credentials file as read-only and store it securely.\n\n---\n\n## Troubleshooting\n\n| Error Code         | Possible Cause \u0026 Solution                      |\n| ------------------ | ---------------------------------------------- |\n| `UNREGISTERED`     | Token is invalid or expired, remove from DB    |\n| `INVALID_ARGUMENT` | Invalid message format, check your payload     |\n| `QUOTA_EXCEEDED`   | FCM quota exceeded, try again later            |\n| `UNAUTHORIZED`     | Invalid credentials, check your key and access |\n| `INTERNAL`         | FCM server error, retry the request            |\n\n---\n\n## Architecture Diagram\n\n```mermaid\nflowchart TD\n    A[Your Go Server] --\u003e|go-fcm| B[FCM API]\n    B --\u003e C[Android/iOS/Web Device]\n    B -.-\u003e D[Topic/Condition Routing]\n```\n\n---\n\n## FAQ\n\n- Q: How do I obtain an FCM device token?\n- Q: How do I set up multi-language notifications?\n- Q: How do I track message delivery status?\n\nFor more, see the [Firebase Official FAQ](https://firebase.google.com/support/faq/)\n\n---\n\n## License\n\nThis project is licensed under the [MIT License](LICENSE).\n\n---\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappleboy%2Fgo-fcm","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fappleboy%2Fgo-fcm","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fappleboy%2Fgo-fcm/lists"}